unit dbconnect;

{$mode DELPHI}{$H+}

interface

uses
  Classes, SysUtils, Generics.Collections, Generics.Defaults, Graphics,
  dbstructures, ExtCtrls, umyTranslate, RegExpr, dbstructures.mysql,
  dbstructures.mssql, dbstructures.postgresql, dbstructures.sqlite,
  dbstructures.interbase, uapijk, strutils;

type
  {$M+}// Needed to add published properties


  TIntegerDynArray = TArray<integer>;
  TCardinalDynArray = TArray<cardinal>;


  TListNodeType = (lntNone, lntDb, lntGroup, lntTable, lntView,
    lntFunction, lntProcedure, lntTrigger, lntEvent, lntColumn);
  TListNodeTypes = set of TListNodeType;
  TDBConnection = class;
  TConnectionParameters = class;
  TDBQuery = class;
  TDBQueryList = TObjectList<TDBQuery>;
  TDBObject = class;

  TColumnPart = (cpAll, cpName, cpType, cpAllowNull, cpDefault,
    cpVirtuality, cpComment, cpCollation);
  TColumnParts = set of TColumnPart;
  TColumnDefaultType = (cdtNothing, cdtText, cdtNull, cdtAutoInc, cdtExpression);
  // General purpose editing status flag
  TEditingStatus = (esUntouched, esModified, esDeleted, esAddedUntouched,
    esAddedModified, esAddedDeleted);

  // Column object, many of them in a TObjectList

  { TTableColumn }

  TTableColumn = class(TPersistent)
  private
    FConnection: TDBConnection;
    FStatus: TEditingStatus;
    procedure SetStatus(Value: TEditingStatus);
  public
    Name, OldName: string;
    DataType, OldDataType: TDBDatatype;
    LengthSet: string;
    Unsigned, AllowNull, ZeroFill, LengthCustomized, Invisible: boolean;
    DefaultType: TColumnDefaultType;
    DefaultText: string;
    OnUpdateType: TColumnDefaultType;
    OnUpdateText: string;
    Comment, Charset, Collation, GenerationExpression, Virtuality: string;
    constructor Create(AOwner: TDBConnection; Serialized: string = '');
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function Serialize: string;
    function SQLCode(OverrideCollation: string = '';
      Parts: TColumnParts = [cpAll]): string;
    function ValueList: TStringList;
    procedure ParseDatatype(Source: string);
    function CastAsText: string;
    property Status: TEditingStatus read FStatus write SetStatus;
    property Connection: TDBConnection read FConnection;
    function AutoIncName: string;
  end;

  PTableColumn = ^TTableColumn;

  { TTableColumnList }

  TTableColumnList = class(TObjectList<TTableColumn>)
  public
    procedure Assign(Source: TTableColumnList);
  end;

  TColumnCache = TDictionary<string, TTableColumnList>;

  { TTableKey }

  TTableKey = class(TPersistent)
  const
    PRIMARY = 'PRIMARY';
    KEY = 'KEY';
    UNIQUE = 'UNIQUE';
    FULLTEXT = 'FULLTEXT';
    SPATIAL = 'SPATIAL';














  private
    FConnection: TDBConnection;
    function GetImageIndex: integer;
  public
    Name, OldName: string;
    IndexType, OldIndexType, Algorithm, Comment: string;
    Columns, SubParts, Collations: TStringList;
    Modified, Added: boolean;
    constructor Create(AOwner: TDBConnection);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    procedure Modification(Sender: TObject);
    function SQLCode: string;
    property ImageIndex: integer read GetImageIndex;
    property Connection: TDBConnection read FConnection;
  end;

  { TTableKeyList }

  TTableKeyList = class(TObjectList<TTableKey>)
  public
    procedure Assign(Source: TTableKeyList);
  end;

  TKeyCache = TDictionary<string, TTableKeyList>;

  // Helper object to manage foreign keys in a TObjectList

  { TForeignKey }

  TForeignKey = class(TPersistent)
  private
    FConnection: TDBConnection;
  public
    KeyName, OldKeyName, Db, ReferenceDb, ReferenceTable, OnUpdate, OnDelete: string;
    Columns, ForeignColumns: TStringList;
    Modified, Added, KeyNameWasCustomized: boolean;
    constructor Create(AOwner: TDBConnection);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function SQLCode(IncludeSymbolName: boolean): string;
    function ReferenceTableObj: TDBObject;
    property Connection: TDBConnection read FConnection;
  end;

  { TForeignKeyList }

  TForeignKeyList = class(TObjectList<TForeignKey>)
  public
    procedure Assign(Source: TForeignKeyList);
  end;

  TForeignKeyCache = TDictionary<string, TForeignKeyList>;

  { TCheckConstraint }

  TCheckConstraint = class(TPersistent)
  private
    FConnection: TDBConnection;
    FName, FCheckClause: string;
    FModified, FAdded: boolean;
  public
    constructor Create(AOwner: TDBConnection);
    procedure Assign(Source: TPersistent); override;
    function SQLCode: string;
    property Connection: TDBConnection read FConnection;
    property Name: string read FName write FName;
    property CheckClause: string read FCheckClause write FCheckClause;
    property Modified: boolean read FModified write FModified;
    property Added: boolean read FAdded write FAdded;
  end;

  { TCheckConstraintList }

  TCheckConstraintList = class(TObjectList<TCheckConstraint>)
  public
    procedure Assign(Source: TCheckConstraintList);
  end;

  TCheckConstraintCache = TDictionary<string, TCheckConstraintList>;

  TRoutineParam = class(TObject)
  public
    Name, Context, Datatype: string;
  end;

  TRoutineParamList = TObjectList<TRoutineParam>;

  { TDBObject }

  TDBObject = class(TPersistent)
  private
    FCreateCode: string;
    FCreateCodeLoaded: boolean;
    FWasSelected: boolean;
    FConnection: TDBConnection;
    function GetObjType: string;
    function GetImageIndex: integer;
    function GetOverlayImageIndex: integer;
    function GetPath: string;
    function GetTableColumns: TTableColumnList;
    function GetTableKeys: TTableKeyList;
    function GetTableForeignKeys: TForeignKeyList;
    function GetTableCheckConstraints: TCheckConstraintList;
  public
    // Table options:
    Name, Schema, Database, Column, Engine, Comment, RowFormat,
    CreateOptions, Collation: string;
    Created, Updated, LastChecked: TDateTime;
    Rows, Size, Version, AvgRowLen, MaxDataLen, IndexLen, DataLen,
    DataFree, AutoInc, CheckSum: int64;
    // Routine options:
    Body, Definer, Returns, DataAccess, Security, ArgTypes: string;
    Deterministic, RowsAreExact: boolean;

    NodeType, GroupType: TListNodeType;
    constructor Create(OwnerConnection: TDBConnection);
    procedure Assign(Source: TPersistent); override;
    procedure UnloadDetails;
    procedure Drop;
    function IsSameAs(CompareTo: TDBObject): boolean;
    function QuotedDatabase(AlwaysQuote: boolean = True): string;
    function QuotedName(AlwaysQuote: boolean = True;
      SeparateSegments: boolean = True): string;
    function QuotedDbAndTableName(AlwaysQuote: boolean = True): string;
    function QuotedColumn(AlwaysQuote: boolean = True): string;
    function SchemaClauseIS(Prefix: string): string;
    function RowCount(Reload: boolean; ForceExact: boolean = False): int64;
    function GetCreateCode: string; overload;
    function GetCreateCode(RemoveAutoInc, RemoveDefiner: boolean): string; overload;
    property ObjType: string read GetObjType;
    property ImageIndex: integer read GetImageIndex;
    property OverlayImageIndex: integer read GetOverlayImageIndex;
    property Path: string read GetPath;
    property CreateCode: string read GetCreateCode;
    property WasSelected: boolean read FWasSelected write FWasSelected;
    property Connection: TDBConnection read FConnection;
    property TableColumns: TTableColumnList read GetTableColumns;
    property TableKeys: TTableKeyList read GetTableKeys;
    property TableForeignKeys: TForeignKeyList read GetTableForeignKeys;
    property TableCheckConstraints: TCheckConstraintList read GetTableCheckConstraints;
  end;

  PDBObject = ^TDBObject;

  TDBObjectList = class(TObjectList<TDBObject>)
  private
    FDatabase: string;
    FDataSize: int64;
    FLargestObjectSize: int64;
    FLastUpdate: TDateTime;
    FCollation: string;
    FOnlyNodeType: TListNodeType;
    FObjectsLoaded: boolean;
  public
    property Database: string read FDatabase;
    property DataSize: int64 read FDataSize;
    property LargestObjectSize: int64 read FLargestObjectSize;
    property LastUpdate: TDateTime read FLastUpdate;
    property Collation: string read FCollation;
    property OnlyNodeType: TListNodeType read FOnlyNodeType;
  end;

  TDatabaseCache = class(TObjectList<TDBObjectList>); // A list of db object lists, used for caching

  TOidStringPairs = TDictionary<POid, string>;

  // Structures for in-memory changes of a TDBQuery

  { TGridValue }

  TGridValue = class(TObject)
  public
    NewText, OldText: string;
    NewIsNull, OldIsNull: boolean;
    NewIsFunction, OldIsFunction: boolean;
    Modified: boolean;
    destructor Destroy; override;
  end;

  TGridRow = class(TObjectList<TGridValue>)
  public
    RecNo: int64;
    Inserted: boolean;
  end;

  TGridRows = class(TObjectList<TGridRow>);


  TSQLFunction = class(TPersistent)
  public
    Name, Declaration, Category, Description: string;
  end;

  { TSQLFunctionList }

  TSQLFunctionList = class(TObjectList<TSQLFunction>)
  private
    FOwner: TDBConnection;
    FCategories: TStringList;
    FNames: TStringList;
  public
    constructor Create(AOwner: TDBConnection; SQLFunctionsFileOrder: string);
    property Categories: TStringList read FCategories;
    property Names: TStringList read FNames;
  end;

  { TConnectionParameters and friends }

  TNetType = (
    ntMySQL_TCPIP,
    ntMySQL_NamedPipe,
    ntMySQL_SSHtunnel,
    ntMSSQL_NamedPipe,
    ntMSSQL_TCPIP,
    ntMSSQL_SPX,
    ntMSSQL_VINES,
    ntMSSQL_RPC,
    ntPgSQL_TCPIP,
    ntPgSQL_SSHtunnel,
    ntSQLite,
    ntMySQL_ProxySQLAdmin,
    ntInterbase_TCPIP,
    ntInterbase_Local,
    ntFirebird_TCPIP,
    ntFirebird_Local,
    ntMySQL_RDS
    );

  TNetTypeGroup = (ngNone, ngMSSQL, ngMySQL, ngOralce, ngPgSQL, ngSQLite, ngInterbase);
  TNetGroupLibs = TDictionary<TNetTypeGroup, TStringList>;

  { TConnectionParameters }

  TConnectionParameters = class(TObject)
  strict private
    FId: integer;
    FNetType: TNetType;
    FNetTypeGroup: TNetTypeGroup;
    FSessionName: string;
    FHostname, FUsername, FPassword, FAllDatabases, FLibraryOrProvider,
    FComment, FStartupScriptFilename, FSessionPath, FSSLPrivateKey,
    FSSLCertificate, FSSLCACertificate, FSSLCipher, FServerVersion,
    FSSHHost, FSSHUser, FSSHPassword, FSSHExe, FSSHPrivateKey,
    FIgnoreDatabasePattern, FInitDataBase: string;
    FPort, FSSHPort, FSSHLocalPort, FSSHTimeout, FCounter, FQueryTimeout,
    FKeepAlive: integer;
    FSSHActive, FLoginPrompt, FCompressed, FLocalTimeZone, FFullTableStatus,
    FWindowsAuth, FWantSSL, FIsFolder, FCleartextPluginEnabled: boolean;
    FSessionColor: TColor;
    FLastConnect: TDateTime;
    FLogFileDdl: boolean;
    FLogFileDml: boolean;
    FLogFilePath: string;
  class var FLibraries: TNetGroupLibs;
    function GetImageIndex: integer;
    function GetSessionName: string;
  public
    constructor Create; overload;
    constructor Create(SessionRegPath: string); overload;
    procedure SaveToRegistry;
    function CreateConnection(AOwner: TComponent): TDBConnection;
    function CreateQuery(Connection: TDbConnection): TDBQuery;
    function NetTypeName(LongFormat: boolean): string;
    function GetNetTypeGroup: TNetTypeGroup;
    function SshSupport: boolean;
    function IsAnyMySQL: boolean;
    function IsAnyMSSQL: boolean;
    function IsAnyPostgreSQL: boolean;
    function IsAnySQLite: boolean;
    function IsAnyInterbase: boolean;
    function IsMariaDB: boolean;
    function IsMySQL(StrictDetect: boolean): boolean;
    function IsPercona: boolean;
    function IsTokudb: boolean;
    function IsInfiniDB: boolean;
    function IsInfobright: boolean;
    function IsProxySQLAdmin: boolean;
    function IsMySQLonRDS: boolean;
    function IsAzure: boolean;
    function IsMemSQL: boolean;
    function IsRedshift: boolean;
    function IsInterbase: boolean;
    function IsFirebird: boolean;
    property ImageIndex: integer read GetImageIndex;
    function GetLibraries: TStringList;
    function DefaultLibrary: string;
    function DefaultHost: string;
    function DefaultPort: integer;
    function DefaultUsername: string;
    function DefaultIgnoreDatabasePattern: string;
    function DefaultSshActive: boolean;
    //function GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String;
  published
    property Id: integer read FId write Fid;
    property IsFolder: boolean read FIsFolder write FIsFolder;
    property NetType: TNetType read FNetType write FNetType;
    property NetTypeGroup: TNetTypeGroup read FNetTypeGroup write FNetTypeGroup;
    // read GetNetTypeGroup;
    property ServerVersion: string read FServerVersion write FServerVersion;
    property Counter: integer read FCounter write FCounter;
    property LastConnect: TDateTime read FLastConnect;
    property SessionPath: string read FSessionPath write FSessionPath;
    property SessionName: string read FSessionName write FSessionName;
    //GetSessionName;
    property SessionColor: TColor read FSessionColor write FSessionColor;
    property Hostname: string read FHostname write FHostname;
    property Port: integer read FPort write FPort;
    property Username: string read FUsername write FUsername;
    property Password: string read FPassword write FPassword;
    property LoginPrompt: boolean read FLoginPrompt write FLoginPrompt;
    property WindowsAuth: boolean read FWindowsAuth write FWindowsAuth;
    property CleartextPluginEnabled: boolean
      read FCleartextPluginEnabled write FCleartextPluginEnabled;
    property InitDataBase: string read FInitDataBase write FInitDataBase;
    property AllDatabasesStr: string read FAllDatabases write FAllDatabases;
    property LibraryOrProvider: string read FLibraryOrProvider write FLibraryOrProvider;
    property Comment: string read FComment write FComment;
    property StartupScriptFilename: string
      read FStartupScriptFilename write FStartupScriptFilename;
    property QueryTimeout: integer read FQueryTimeout write FQueryTimeout;
    property KeepAlive: integer read FKeepAlive write FKeepAlive;
    property Compressed: boolean read FCompressed write FCompressed;
    property LocalTimeZone: boolean read FLocalTimeZone write FLocalTimeZone;
    property FullTableStatus: boolean read FFullTableStatus write FFullTableStatus;
    property SSHActive: boolean read FSSHActive write FSSHActive;
    property SSHHost: string read FSSHHost write FSSHHost;
    property SSHPort: integer read FSSHPort write FSSHPort;
    property SSHUser: string read FSSHUser write FSSHUser;
    property SSHPassword: string read FSSHPassword write FSSHPassword;
    property SSHTimeout: integer read FSSHTimeout write FSSHTimeout;
    property SSHPrivateKey: string read FSSHPrivateKey write FSSHPrivateKey;
    property SSHLocalPort: integer read FSSHLocalPort write FSSHLocalPort;
    property SSHExe: string read FSSHExe write FSSHExe;
    property WantSSL: boolean read FWantSSL write FWantSSL;
    property SSLPrivateKey: string read FSSLPrivateKey write FSSLPrivateKey;
    property SSLCertificate: string read FSSLCertificate write FSSLCertificate;
    property SSLCACertificate: string read FSSLCACertificate write FSSLCACertificate;
    property SSLCipher: string read FSSLCipher write FSSLCipher;
    property IgnoreDatabasePattern: string
      read FIgnoreDatabasePattern write FIgnoreDatabasePattern;
    property LogFileDdl: boolean read FLogFileDdl write FLogFileDdl;
    property LogFileDml: boolean read FLogFileDml write FLogFileDml;
    property LogFilePath: string read FLogFilePath write FLogFilePath;
  end;

  PConnectionParameters = ^TConnectionParameters;

  { TDBConnection }

  TDBLogCategory = (lcInfo, lcSQL, lcUserFiredSQL, lcError, lcDebug, lcScript);

  TDBLogItem = class(TObject)
  public
    Category: TDBLogCategory;
    LineText: string;
    Connection: TDBConnection;
  end;

  TDBLogItems = TObjectList<TDBLogItem>;
  TDBLogEvent = procedure(Msg: string; Category: TDBLogCategory = lcInfo;
    Connection: TDBConnection = nil) of object;
  TDBEvent = procedure(Connection: TDBConnection; Database: string) of object;
  TDBDataTypeArray = array of TDBDataType;
  TSQLSpecifityId = (spDatabaseTable, spDatabaseTableId, spDatabaseDrop,
    spDbObjectsTable, spDbObjectsCreateCol, spDbObjectsUpdateCol, spDbObjectsTypeCol,
    spEmptyTable, spRenameTable, spRenameView, spCurrentUserHost, spLikeCompare,
    spAddColumn, spChangeColumn, spRenameColumn, spForeignKeyEventAction,
    spGlobalStatus, spCommandsCounters, spSessionVariables, spGlobalVariables,
    spISSchemaCol,
    spUSEQuery, spKillQuery, spKillProcess,
    spFuncLength, spFuncCeil, spFuncLeft, spFuncNow, spFuncLastAutoIncNumber,
    spLockedTables, spDisableForeignKeyChecks, spEnableForeignKeyChecks,
    spOrderAsc, spOrderDesc);

  TDBConnection = class(TComponent)
  private
    FActive: boolean;
    FConnectionStarted: cardinal;
    FServerUptime: integer;
    FServerDateTimeOnStartup: string;
    FParameters: TConnectionParameters;
    //FSecureShellCmd: TSecureShellCmd;
    FLoginPromptDone: boolean;
    FDatabase: string;
    FAllDatabases: TStringList;
    FLogPrefix: string;
    FOnLog: TDBLogEvent;
    FOnConnected: TDBEvent;
    FOnDatabaseChanged: TDBEvent;
    FOnObjectnamesChanged: TDBEvent;
    FRowsFound: int64;
    FRowsAffected: int64;
    FWarningCount: cardinal;
    FServerOS: string;
    FServerVersionUntouched: string;
    FRealHostname: string;
    FLastQueryDuration, FLastQueryNetworkDuration: cardinal;
    FLastQuerySQL: string;
    FIsUnicode: boolean;
    FIsSSL: boolean;
    FTableEngines: TStringList;
    FTableEngineDefault: string;
    FCollationTable: TDBQuery;
    FCharsetTable: TDBQuery;
    FSessionVariables: TDBQuery;
    FInformationSchemaObjects: TStringList;
    FDatabaseCache: TDatabaseCache;
    FColumnCache: TColumnCache;
    FKeyCache: TKeyCache;
    FForeignKeyCache: TForeignKeyCache;
    FCheckConstraintCache: TCheckConstraintCache;
    FCurrentUserHostCombination: string;
    FAllUserHostCombinations: TStringList;
    FLockedByThread: TThread;
    FStringQuoteChar: char;
    FQuoteChar: char;
    FQuoteChars: string;
    FDatatypes: TDBDataTypeArray;
    FThreadID: int64;
    FSQLSpecifities: array[TSQLSpecifityId] of string;
    FKeepAliveTimer: TTimer;
    FFavorites: TStringList;
    FPrefetchResults: TDBQueryList;
    FForeignKeyQueriesFailed: boolean;
    FInfSch: string;
    FIdentCharsNoQuote: TSysCharSet;
    FMaxRowsPerInsert: int64;
    FCaseSensitivity: integer;
    FSQLFunctions: TSQLFunctionList;
    procedure SetActive(Value: boolean); virtual; abstract;
    procedure DoBeforeConnect; virtual;
    procedure StartSSHTunnel(var FinalHost: string; var FinalPort: integer);
    procedure EndSSHTunnel;
    procedure DoAfterConnect; virtual;
    procedure DetectUSEQuery(SQL: string); virtual;
    procedure SetDatabase(Value: string);
    function GetThreadId: int64; virtual; abstract;
    function GetCharacterSet: string; virtual;
    procedure SetCharacterSet(CharsetName: string); virtual;
    function GetLastErrorCode: cardinal; virtual; abstract;
    function GetLastErrorMsg: string; virtual; abstract;
    function GetAllDatabases: TStringList; virtual;
    procedure ApplyIgnoreDatabasePattern(Dbs: TStringList);
    function GetTableEngines: TStringList; virtual;
    function GetCollationTable: TDBQuery; virtual;
    function GetCollationList: TStringList; virtual;
    function GetCharsetTable: TDBQuery; virtual;
    function GetCharsetList: TStringList;
    function GetConnectionUptime: integer;
    function GetServerUptime: integer;
    function GetServerNow: TDateTime;
    function GetCurrentUserHostCombination: string;
    function GetAllUserHostCombinations: TStringList;
    function DecodeAPIString(a: ansistring): string;
    function GetRowCount(Obj: TDBObject; ForceExact: boolean = False): int64;
      virtual; abstract;
    procedure ClearCache(IncludeDBObjects: boolean);
    procedure FetchDbObjects(db: string; var Cache: TDBObjectList); virtual; abstract;
    procedure SetLockedByThread(Value: TThread); virtual;
    procedure KeepAliveTimerEvent(Sender: TObject);
    procedure Drop(Obj: TDBObject); virtual;
    procedure PrefetchResults(SQL: string);
    procedure FreeResults(Results: TDBQuery);
    function IsTextDefault(Value: string; Tp: TDBDatatype): boolean;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Query(SQL: string; DoStoreResult: boolean = False;
      LogCategory: TDBLogCategory = lcSQL); virtual;
    procedure Log(Category: TDBLogCategory; Msg: string);
    function EscapeString(Text: string; ProcessJokerChars: boolean = False;
      DoQuote: boolean = True): string; overload;
    function EscapeString(Text: string; Datatype: TDBDatatype): string; overload;
    function QuoteIdent(Identifier: string; AlwaysQuote: boolean = True;
      Glue: char = #0): string;
    function DeQuoteIdent(Identifier: string; Glue: char = #0): string;
    function CleanIdent(Identifier: string): string;
    function QuotedDbAndTableName(DB, Obj: string): string;
    function FindObject(DB, Obj: string): TDBObject;
    function escChars(const Text: string;
      EscChar, Char1, Char2, Char3, Char4: char): string;
    function UnescapeString(Text: string): string;
    function ExtractLiteral(var SQL: string; Prefix: string): string;
    function GetResults(SQL: string): TDBQuery;
    function GetCol(SQL: string; Column: integer = 0): TStringList;
    function GetVar(SQL: string; Column: integer = 0): string; overload;
    function GetVar(SQL: string; Column: string): string; overload;
    function Ping(Reconnect: boolean): boolean; virtual; abstract;
    function RefreshAllDatabases: TStringList;
    function GetDBObjects(db: string; Refresh: boolean = False;
      OnlyNodeType: TListNodeType = lntNone): TDBObjectList;
    function DbObjectsCached(db: string): boolean;
    function ParseDateTime(Str: string): TDateTime;
    function GetKeyColumns(Columns: TTableColumnList;
      Keys: TTableKeyList): TStringList;
    function ConnectionInfo: TStringList; virtual;
    function GetLastResults: TDBQueryList; virtual;
    function GetCreateCode(Obj: TDBObject): string; virtual;
    procedure PrefetchCreateCode(Objects: TDBObjectList);
    function GetSessionVariables(Refresh: boolean): TDBQuery;
    function GetSessionVariable(VarName: string; DefaultValue: string = '';
      Refresh: boolean = False): string;
    function MaxAllowedPacket: int64; virtual;
    function GetSQLSpecifity(Specifity: TSQLSpecifityId): string; overload;
    function GetSQLSpecifity(Specifity: TSQLSpecifityId;
      const Args: array of const): string; overload;
    function GetDateTimeValue(Input: string; Datatype: TDBDatatypeIndex): string;
    procedure ClearDbObjects(db: string);
    procedure ClearAllDbObjects;
    procedure ParseViewStructure(CreateCode: string; DBObj: TDBObject;
      var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: string);
    procedure ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList);
    procedure PurgePrefetchResults;
    function GetDatatypeByName(var DataType: string; DeleteFromSource: boolean;
      Identifier: string = ''): TDBDatatype;
    function GetDatatypeByNativeType(NativeType: integer;
      Identifier: string = ''): TDBDatatype;
    function ApplyLimitClause(QueryType, QueryBody: string;
      Limit, Offset: int64): string;
    function LikeClauseTail: string;
    property Parameters: TConnectionParameters read FParameters write FParameters;
    property ThreadId: int64 read GetThreadId;
    property ConnectionUptime: integer read GetConnectionUptime;
    property ServerUptime: integer read GetServerUptime;
    property ServerNow: TDateTime read GetServerNow;
    property CharacterSet: string read GetCharacterSet write SetCharacterSet;
    property LastErrorCode: cardinal read GetLastErrorCode;
    property LastErrorMsg: string read GetLastErrorMsg;
    property ServerOS: string read FServerOS;
    property ServerVersionUntouched: string read FServerVersionUntouched;
    property ColumnCache: TColumnCache read FColumnCache;
    property KeyCache: TKeyCache read FKeyCache;
    property ForeignKeyCache: TForeignKeyCache read FForeignKeyCache;
    property CheckConstraintCache: TCheckConstraintCache read FCheckConstraintCache;
    property QuoteChar: char read FQuoteChar;
    property QuoteChars: string read FQuoteChars;
    function ServerVersionStr: string;
    function ServerVersionInt: integer;
    function NdbClusterVersionInt: integer;
    property RowsFound: int64 read FRowsFound;
    property RowsAffected: int64 read FRowsAffected;
    property WarningCount: cardinal read FWarningCount;
    property LastQueryDuration: cardinal read FLastQueryDuration;
    property LastQueryNetworkDuration: cardinal read FLastQueryNetworkDuration;
    property IsUnicode: boolean read FIsUnicode;
    property IsSSL: boolean read FIsSSL;
    property AllDatabases: TStringList read GetAllDatabases;
    property TableEngines: TStringList read GetTableEngines;
    property TableEngineDefault: string read FTableEngineDefault;
    property CollationTable: TDBQuery read GetCollationTable;
    property CollationList: TStringList read GetCollationList;
    property CharsetTable: TDBQuery read GetCharsetTable;
    property CharsetList: TStringList read GetCharsetList;
    property InformationSchemaObjects: TStringList read FInformationSchemaObjects;
    function ResultCount: integer;
    property CurrentUserHostCombination: string read GetCurrentUserHostCombination;
    property AllUserHostCombinations: TStringList read GetAllUserHostCombinations;
    property LockedByThread: TThread read FLockedByThread write SetLockedByThread;
    property Datatypes: TDBDataTypeArray read FDatatypes;
    property Favorites: TStringList read FFavorites;
    property InfSch: string read FInfSch;
    function GetLockedTableCount(db: string): integer;
    function IdentifierEquals(Ident1, Ident2: string): boolean;
    function GetTableColumns(Table: TDBObject): TTableColumnList; virtual;
    function GetTableKeys(Table: TDBObject): TTableKeyList; virtual;
    function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; virtual;
    function GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList; virtual;
    property MaxRowsPerInsert: int64 read FMaxRowsPerInsert;
    property SQLFunctions: TSQLFunctionList read FSQLFunctions;
    function IsNumeric(Text: string): boolean;
    function IsHex(Text: string): boolean;
  published
    property Active: boolean read FActive write SetActive default False;
    property Database: string read FDatabase write SetDatabase;
    property LogPrefix: string read FLogPrefix write FLogPrefix;
    property OnLog: TDBLogEvent read FOnLog write FOnLog;
    property OnConnected: TDBEvent read FOnConnected write FOnConnected;
    property OnDatabaseChanged: TDBEvent read FOnDatabaseChanged
      write FOnDatabaseChanged;
    property OnObjectnamesChanged: TDBEvent
      read FOnObjectnamesChanged write FOnObjectnamesChanged;
  end;

  TDBConnectionList = TObjectList<TDBConnection>;

  { TMySQLConnection }

  TMySQLRawResults = array of PMYSQL_RES;

  TMySQLConnection = class(TDBConnection)
  private
    FHandle: PMYSQL;
    FLib: TMySQLLib;
    FLastRawResults: TMySQLRawResults;
    FStatementNum: cardinal;
    procedure SetActive(Value: boolean); override;
    procedure DoBeforeConnect; override;
    procedure DoAfterConnect; override;
    function GetThreadId: int64; override;
    function GetCharacterSet: string; override;
    procedure SetCharacterSet(CharsetName: string); override;
    function GetLastErrorCode: cardinal; override;
    function GetLastErrorMsg: string; override;
    function GetAllDatabases: TStringList; override;
    function GetTableEngines: TStringList; override;
    function GetCollationTable: TDBQuery; override;
    function GetCharsetTable: TDBQuery; override;
    function GetCreateViewCode(Database, Name: string): string;
    function GetRowCount(Obj: TDBObject; ForceExact: boolean = False): int64; override;
    procedure FetchDbObjects(db: string; var Cache: TDBObjectList); override;
    procedure SetLockedByThread(Value: TThread); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Lib: TMySQLLib read FLib;
    procedure Query(SQL: string; DoStoreResult: boolean = False;
      LogCategory: TDBLogCategory = lcSQL); override;
    function Ping(Reconnect: boolean): boolean; override;
    function ConnectionInfo: TStringList; override;
    function GetCreateCode(Obj: TDBObject): string; override;
    property LastRawResults: TMySQLRawResults read FLastRawResults;
    function MaxAllowedPacket: int64; override;
    function GetTableColumns(Table: TDBObject): TTableColumnList; override;
    function GetTableKeys(Table: TDBObject): TTableKeyList; override;
  end;


  { TAdoDBConnection }
  TAdoRawResults = array of PQIUSQL_RES;

  TAdoDBConnection = class(TDBConnection)
  private
    //FAdoHandle: TSQLConnection;
    FHandle: PQiuSQL;
    FLastRawResults: TAdoRawResults;
    FStatementNum: cardinal;
    FLastError: string;
    procedure SetActive(Value: boolean); override;
    procedure DoAfterConnect; override;
    function GetThreadId: int64; override;
    function GetLastErrorCode: cardinal; override;
    function GetLastErrorMsg: string; override;
    function GetAllDatabases: TStringList; override;
    function GetCollationTable: TDBQuery; override;
    function GetCharsetTable: TDBQuery; override;
    function GetRowCount(Obj: TDBObject; ForceExact: boolean = False): int64; override;
    procedure FetchDbObjects(db: string; var Cache: TDBObjectList); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Query(SQL: string; DoStoreResult: boolean = False;
      LogCategory: TDBLogCategory = lcSQL); override;
    function Ping(Reconnect: boolean): boolean; override;
    function ConnectionInfo: TStringList; override;
    function GetLastResults: TDBQueryList; override;
    property LastRawResults: TAdoRawResults read FLastRawResults;
    function GetTableColumns(Table: TDBObject): TTableColumnList; override;
    function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override;
  end;


  TSQLiteConnection = class;

  //TSQLiteGridRows = class(TGridRows)
  //private
  //  FConnection: TSQLiteConnection;
  //public
  //  Statement: Psqlite3_stmt; // Used for querying result structures
  //  constructor Create(AOwner: TSQLiteConnection);
  //  destructor Destroy; override;
  //end;

  //TSQLiteRawResults = array of TSQLiteGridRows;

  TSQLiteRawResults = array of string;

  { TSQLiteConnection }

  TSQLiteConnection = class(TDBConnection)
  private
    //FHandle: Psqlite3;
    //FLib: TSQLiteLib;
    FLastRawResults: TSQLiteRawResults;
    FMainDbName: utf8string;
    procedure SetActive(Value: boolean); override;
    procedure DoBeforeConnect; override;
    function GetThreadId: int64; override;
    function GetLastErrorCode: cardinal; override;
    function GetLastErrorMsg: string; override;
    function GetAllDatabases: TStringList; override;
    function GetCollationList: TStringList; override;
    function GetCharsetTable: TDBQuery; override;
    procedure FetchDbObjects(db: string; var Cache: TDBObjectList); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    //property Lib: TSQLiteLib read FLib;
    procedure Query(SQL: string; DoStoreResult: boolean = False;
      LogCategory: TDBLogCategory = lcSQL); override;
    function Ping(Reconnect: boolean): boolean; override;
    function GetCreateCode(Obj: TDBObject): string; override;
    function GetRowCount(Obj: TDBObject; ForceExact: boolean = False): int64; override;
    property LastRawResults: TSQLiteRawResults read FLastRawResults;
    function GetTableColumns(Table: TDBObject): TTableColumnList; override;
    function GetTableKeys(Table: TDBObject): TTableKeyList; override;
    function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override;
  end;

  //  TInterbaseRawResults = Array of TFDQuery;
  //  TIbDrivers = TDictionary<String, TFDPhysIBDriverLink>;
  //  TFbDrivers = TDictionary<String, TFDPhysFBDriverLink>;
  //  TInterbaseConnection = class(TDBConnection)
  //    private
  //      FFDHandle: TFDConnection;
  //      FLastError: String;
  //      FLastErrorCode: Integer;
  //      FLastRawResults: TInterbaseRawResults;
  //      class var FIbDrivers: TIbDrivers;
  //      class var FFbDrivers: TFbDrivers;
  //      procedure SetActive(Value: Boolean); override;
  //      procedure DoBeforeConnect; override;
  //      function GetThreadId: Int64; override;
  //      procedure OnFdError(ASender: TObject; AInitiator: TObject; var AException: Exception);
  //      function GetLastErrorCode: Cardinal; override;
  //      function GetLastErrorMsg: String; override;
  //      function GetAllDatabases: TStringList; override;
  //      function GetCollationTable: TDBQuery; override;
  //      function GetCharsetTable: TDBQuery; override;
  //      procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override;
  //    public
  //      constructor Create(AOwner: TComponent); override;
  //      destructor Destroy; override;
  //      procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override;
  //      function Ping(Reconnect: Boolean): Boolean; override;
  //      function GetCreateCode(Obj: TDBObject): String; override;
  //      function GetRowCount(Obj: TDBObject; ForceExact: Bool=False): Int64; override;
  //      property LastRawResults: TInterbaseRawResults read FLastRawResults;
  //      function GetTableColumns(Table: TDBObject): TTableColumnList; override;
  //      function GetTableKeys(Table: TDBObject): TTableKeyList; override;
  //      function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override;
  //  end;


  { TDBQuery }

  TDBQuery = class(TComponent)
  private
    FSQL: string;
    FConnection: TDBConnection;
    FRecNo, FRecordCount: int64;
    FColumnNames: TStringList;
    FColumnOrgNames: TStringList;
    FAutoIncrementColumn: integer;
    FColumnTypes: array of TDBDatatype;
    FColumnLengths: TIntegerDynArray;
    FColumnFlags: TCardinalDynArray;
    FCurrentUpdateRow: TGridRow;
    FEof: boolean;
    FStoreResult: boolean;
    FColumns: TTableColumnList;
    FKeys: TTableKeyList;
    FForeignKeys: TForeignKeyList;
    FEditingPrepared: boolean;
    FUpdateData: TGridRows;
    FDBObject: TDBObject;
    FFormatSettings: TFormatSettings;
    procedure SetRecNo(Value: int64); virtual; abstract;
    function ColumnExists(Column: integer): boolean;
    procedure SetColumnOrgNames(Value: TStringList);
    procedure SetDBObject(Value: TDBObject);
    procedure CreateUpdateRow;
    function GetKeyColumns: TStringList;
    function GridQuery(QueryType, QueryBody: string): string;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Execute(AddResult: boolean = False; UseRawResult: integer = -1);
      virtual; abstract;
    procedure First;
    procedure Next;
    function ColumnCount: integer;
    function GetColBinData(Column: integer; var baData: TBytes): boolean; virtual;
    function Col(Column: integer; IgnoreErrors: boolean = False): string;
      overload; virtual; abstract;
    function Col(ColumnName: string; IgnoreErrors: boolean = False): string; overload;
    function ColumnLengths(Column: integer): int64; virtual;
    function HexValue(Column: integer; IgnoreErrors: boolean = False): string; overload;
    function HexValue(BinValue: string): string; overload;
    function HexValue(var ByteData: TBytes): string; overload;
    function DataType(Column: integer): TDBDataType;
    function MaxLength(Column: integer): int64;
    function ValueList(Column: integer): TStringList;
    // Todo: overload ColumnExists:
    function ColExists(Column: string): boolean;
    function ColIsPrimaryKeyPart(Column: integer): boolean; virtual; abstract;
    function ColIsUniqueKeyPart(Column: integer): boolean; virtual; abstract;
    function ColIsKeyPart(Column: integer): boolean; virtual; abstract;
    function ColIsVirtual(Column: integer): boolean;
    function ColAttributes(Column: integer): TTableColumn;
    function IsNull(Column: integer): boolean; overload; virtual; abstract;
    function IsNull(Column: string): boolean; overload;
    function IsFunction(Column: integer): boolean;
    function HasResult: boolean; virtual; abstract;
    function GetWhereClause: string;
    procedure CheckEditable;
    function IsEditable: boolean;
    procedure DeleteRow;
    function InsertRow: int64;
    procedure SetCol(Column: integer; NewText: string; Null: boolean;
      IsFunction: boolean);
    function EnsureFullRow(Refresh: boolean): boolean;
    function HasFullData: boolean;
    function Modified(Column: integer): boolean; overload;
    function Modified: boolean; overload;
    function Inserted: boolean;
    function SaveModifications: boolean;
    function DatabaseName: string; virtual; abstract;
    function TableName: string; overload;
    function TableName(Column: integer): string; overload; virtual; abstract;
    function QuotedDbAndTableName: string;
    procedure DiscardModifications;
    procedure PrepareColumnAttributes;
    procedure PrepareEditing;
    property RecNo: int64 read FRecNo write SetRecNo;
    property EOF: boolean read FEof;
    property RecordCount: int64 read FRecordCount;
    property ColumnNames: TStringList read FColumnNames;
    property StoreResult: boolean read FStoreResult write FStoreResult;
    property ColumnOrgNames: TStringList read FColumnOrgNames write SetColumnOrgNames;
    property AutoIncrementColumn: integer read FAutoIncrementColumn;
    property DBObject: TDBObject read FDBObject write SetDBObject;
    property SQL: string read FSQL write FSQL;
    property Connection: TDBConnection read FConnection;
  end;

  PDBQuery = ^TDBQuery;

  TGoRows = array of string;

  TGoROW = string;

  { TMySQLQuery }

  TMySQLQuery = class(TDBQuery)
  private
    FConnection: TMySQLConnection;
    FResultList: TMySQLRawResults;
    FCurrentResults: TGoRows;
    FCurrentRow: TGoROW;
    procedure SetRecNo(Value: int64); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Execute(AddResult: boolean = False; UseRawResult: integer = -1); override;
    function GetColBinData(Column: integer; var baData: TBytes): boolean; override;
    function Col(Column: integer; IgnoreErrors: boolean = False): string;
      overload; override;
    function ColIsPrimaryKeyPart(Column: integer): boolean; override;
    function ColIsUniqueKeyPart(Column: integer): boolean; override;
    function ColIsKeyPart(Column: integer): boolean; override;
    function IsNull(Column: integer): boolean; overload; override;
    function HasResult: boolean; override;
    function DatabaseName: string; override;
    function TableName(Column: integer): string; overload; override;
  end;

  { TAdoDBQuery }

  TAdoDBQuery = class(TDBQuery)
  private
    FCurrentResults: TGoRows;
    FResultList: array of TAdoRawResults;
    procedure SetRecNo(Value: int64); override;
  public
    destructor Destroy; override;
    procedure Execute(AddResult: boolean = False; UseRawResult: integer = -1); override;
    function Col(Column: integer; IgnoreErrors: boolean = False): string;
      overload; override;
    function ColIsPrimaryKeyPart(Column: integer): boolean; override;
    function ColIsUniqueKeyPart(Column: integer): boolean; override;
    function ColIsKeyPart(Column: integer): boolean; override;
    function IsNull(Column: integer): boolean; overload; override;
    function HasResult: boolean; override;
    function DatabaseName: string; override;
    function TableName(Column: integer): string; overload; override;
  end;

  //TPGQuery = class(TDBQuery)
  //private
  //  FConnection: TPgConnection;
  //  FCurrentResults: PPGresult;
  //  FRecNoLocal: integer;
  //  FResultList: TPGRawResults;
  //  procedure SetRecNo(Value: int64); override;
  //public
  //  constructor Create(AOwner: TComponent); override;
  //  destructor Destroy; override;
  //  procedure Execute(AddResult: boolean = False; UseRawResult: integer = -1); override;
  //  function Col(Column: integer; IgnoreErrors: boolean = False): string;
  //    overload; override;
  //  function ColIsPrimaryKeyPart(Column: integer): boolean; override;
  //  function ColIsUniqueKeyPart(Column: integer): boolean; override;
  //  function ColIsKeyPart(Column: integer): boolean; override;
  //  function IsNull(Column: integer): boolean; overload; override;
  //  function HasResult: boolean; override;
  //  function DatabaseName: string; override;
  //  function TableName(Column: integer): string; overload; override;
  //end;

  { TSQLiteQuery }

  TSQLiteQuery = class(TDBQuery)
  private
    FConnection: TSQLiteConnection;
    FCurrentResults: TSQLiteRawResults;
    FRecNoLocal: integer;
    FResultList: TSQLiteRawResults;
    procedure SetRecNo(Value: int64); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Execute(AddResult: boolean = False; UseRawResult: integer = -1); override;
    function Col(Column: integer; IgnoreErrors: boolean = False): string;
      overload; override;
    function ColIsPrimaryKeyPart(Column: integer): boolean; override;
    function ColIsUniqueKeyPart(Column: integer): boolean; override;
    function ColIsKeyPart(Column: integer): boolean; override;
    function IsNull(Column: integer): boolean; overload; override;
    function HasResult: boolean; override;
    function DatabaseName: string; override;
    function TableName(Column: integer): string; overload; override;
  end;



implementation

uses appTool;

  { TConnectionParameters }

function TConnectionParameters.GetImageIndex: integer;
begin

end;

function TConnectionParameters.GetSessionName: string;
begin

end;

constructor TConnectionParameters.Create;
begin

end;

constructor TConnectionParameters.Create(SessionRegPath: string);
begin

end;

procedure TConnectionParameters.SaveToRegistry;
begin

end;

function TConnectionParameters.CreateConnection(AOwner: TComponent): TDBConnection;
begin
  case NetTypeGroup of
    ngMySQL:
      Result := TMySQLConnection.Create(AOwner);
    ngMSSQL:
      Result := TAdoDBConnection.Create(AOwner);
    //ngPgSQL:
    //Result := TPgConnection.Create(AOwner);
    ngSQLite:
      Result := TSQLiteConnection.Create(AOwner);
    ngInterbase:
      //      Result := TInterbaseConnection.Create(AOwner);
    else
      raise Exception.CreateFmt(_(MsgUnhandledNetType), [integer(FNetType)]);
  end;
  Result.Parameters := Self;
end;

function TConnectionParameters.CreateQuery(Connection: TDbConnection): TDBQuery;
begin
  case NetTypeGroup of
    ngMySQL:
      Result := TMySQLQuery.Create(Connection);
    ngMSSQL:
      Result := TAdoDBQuery.Create(Connection);
    //ngPgSQL:
    //  Result := TPGQuery.Create(Connection);
    ngSQLite:
      Result := TSQLiteQuery.Create(Connection);
    ngInterbase:
      //      Result := TInterbaseQuery.Create(Connection);
    else
      raise Exception.CreateFmt(_(MsgUnhandledNetType), [integer(FNetType)]);
  end;
end;

function TConnectionParameters.NetTypeName(LongFormat: boolean): string;
begin

end;

function TConnectionParameters.GetNetTypeGroup: TNetTypeGroup;
begin

end;

function TConnectionParameters.SshSupport: boolean;
begin

end;

function TConnectionParameters.IsAnyMySQL: boolean;
begin

end;

function TConnectionParameters.IsAnyMSSQL: boolean;
begin

end;

function TConnectionParameters.IsAnyPostgreSQL: boolean;
begin

end;

function TConnectionParameters.IsAnySQLite: boolean;
begin

end;

function TConnectionParameters.IsAnyInterbase: boolean;
begin

end;

function TConnectionParameters.IsMariaDB: boolean;
begin

end;

function TConnectionParameters.IsMySQL(StrictDetect: boolean): boolean;
begin

end;

function TConnectionParameters.IsPercona: boolean;
begin

end;

function TConnectionParameters.IsTokudb: boolean;
begin

end;

function TConnectionParameters.IsInfiniDB: boolean;
begin

end;

function TConnectionParameters.IsInfobright: boolean;
begin

end;

function TConnectionParameters.IsProxySQLAdmin: boolean;
begin

end;

function TConnectionParameters.IsMySQLonRDS: boolean;
begin

end;

function TConnectionParameters.IsAzure: boolean;
begin

end;

function TConnectionParameters.IsMemSQL: boolean;
begin

end;

function TConnectionParameters.IsRedshift: boolean;
begin

end;

function TConnectionParameters.IsInterbase: boolean;
begin

end;

function TConnectionParameters.IsFirebird: boolean;
begin

end;

function TConnectionParameters.GetLibraries: TStringList;
begin

end;

function TConnectionParameters.DefaultLibrary: string;
begin

end;

function TConnectionParameters.DefaultHost: string;
begin

end;

function TConnectionParameters.DefaultPort: integer;
begin

end;

function TConnectionParameters.DefaultUsername: string;
begin

end;

function TConnectionParameters.DefaultIgnoreDatabasePattern: string;
begin

end;

function TConnectionParameters.DefaultSshActive: boolean;
begin

end;

{ TDBConnection }

procedure TDBConnection.DoBeforeConnect;
var
  UsingPass: string;
  //Dialog: TfrmLogin;
begin
  // Prompt for password on initial connect
  //if FParameters.LoginPrompt and (not FLoginPromptDone) then begin
  //  Dialog := TfrmLogin.Create(Self);
  //  Dialog.Caption := APPNAME + ' - ' + FParameters.SessionName;
  //  Dialog.lblPrompt.Caption := f_('Login to %s:', [FParameters.Hostname]);
  //  Dialog.editUsername.Text := FParameters.Username;
  //  Dialog.editPassword.Text := FParameters.Password;
  //  Dialog.ShowModal;
  //  FParameters.Username := Dialog.editUsername.Text;
  //  FParameters.Password := Dialog.editPassword.Text;
  //  Dialog.Free;
  //  FLoginPromptDone := True;
  //end;

  // Prepare connection
  if FParameters.Password <> '' then UsingPass := 'Yes'
  else
    UsingPass := 'No';
  Log(lcInfo, f_('Connecting to %s via %s, username %s, using password: %s ...',
    [FParameters.Hostname, FParameters.NetTypeName(True), FParameters.Username,
    UsingPass]));

  FSQLSpecifities[spOrderAsc] := 'ASC';
  FSQLSpecifities[spOrderDesc] := 'DESC';
  FSQLSpecifities[spForeignKeyEventAction] := 'RESTRICT,CASCADE,SET NULL,NO ACTION';

  case Parameters.NetTypeGroup of
    ngMySQL: begin
      FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s';
      FSQLSpecifities[spEmptyTable] := 'TRUNCATE ';
      FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s';
      FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable];
      FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER()';
      FSQLSpecifities[spLikeCompare] := '%s LIKE %s';
      FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s';
      FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s';
      FSQLSpecifities[spGlobalStatus] :=
        IfThen(Parameters.IsProxySQLAdmin, 'SELECT * FROM stats_mysql_global',
        'SHOW /*!50002 GLOBAL */ STATUS');
      FSQLSpecifities[spCommandsCounters] :=
        IfThen(Parameters.IsProxySQLAdmin,
        'SELECT * FROM stats_mysql_commands_counters',
        'SHOW /*!50002 GLOBAL */ STATUS LIKE ''Com\_%''');
      FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES';
      FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES';
      FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA';
      FSQLSpecifities[spUSEQuery] := 'USE %s';
      if Parameters.NetType = ntMySQL_RDS then
      begin
        FSQLSpecifities[spKillQuery] := 'CALL mysql.rds_kill_query(%d)';
        FSQLSpecifities[spKillProcess] := 'CALL mysql.rds_kill(%d)';
      end
      else
      begin
        FSQLSpecifities[spKillQuery] := 'KILL %d';
        // may be overwritten in DoAfterConnect
        FSQLSpecifities[spKillProcess] := 'KILL %d';
      end;
      FSQLSpecifities[spFuncLength] := 'LENGTH';
      FSQLSpecifities[spFuncCeil] := 'CEIL';
      FSQLSpecifities[spFuncLeft] :=
        IfThen(Parameters.IsProxySQLAdmin, 'SUBSTR(%s, 1, %d)', 'LEFT(%s, %d)');
      FSQLSpecifities[spFuncNow] :=
        IfThen(Parameters.IsProxySQLAdmin, 'CURRENT_TIMESTAMP', 'NOW()');
      FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
      FSQLSpecifities[spLockedTables] := '';
      FSQLSpecifities[spDisableForeignKeyChecks] :=
        'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0';
      FSQLSpecifities[spEnableForeignKeyChecks] :=
        'SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)';
    end;
    ngMSSQL: begin
      FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s';
      FSQLSpecifities[spEmptyTable] := 'DELETE FROM ';
      FSQLSpecifities[spRenameTable] := 'EXEC sp_rename %s, %s';
      FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable];
      FSQLSpecifities[spCurrentUserHost] := 'SELECT SYSTEM_USER';
      FSQLSpecifities[spLikeCompare] := '%s LIKE %s';
      FSQLSpecifities[spAddColumn] := 'ADD %s';
      FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s';
      FSQLSpecifities[spSessionVariables] :=
        'SELECT ' + QuoteIdent('comment') + ', ' + QuoteIdent('value') +
        ' FROM ' + QuoteIdent('master') + '.' + QuoteIdent('dbo') +
        '.' + QuoteIdent('syscurconfigs') + ' ORDER BY ' + QuoteIdent('comment');
      FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables];
      FSQLSpecifities[spISSchemaCol] := '%s_CATALOG';
      FSQLSpecifities[spUSEQuery] := 'USE %s';
      FSQLSpecifities[spKillQuery] := 'KILL %d';
      FSQLSpecifities[spKillProcess] := 'KILL %d';
      FSQLSpecifities[spFuncLength] := 'LEN';
      FSQLSpecifities[spFuncCeil] := 'CEILING';
      FSQLSpecifities[spFuncLeft] := 'LEFT(%s, %d)';
      FSQLSpecifities[spFuncNow] := 'GETDATE()';
      FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
      FSQLSpecifities[spLockedTables] := '';
      FSQLSpecifities[spDisableForeignKeyChecks] := '';
      FSQLSpecifities[spEnableForeignKeyChecks] := '';
    end;
    ngPgSQL: begin
      FSQLSpecifities[spDatabaseDrop] := 'DROP SCHEMA %s';
      FSQLSpecifities[spEmptyTable] := 'DELETE FROM ';
      FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s';
      FSQLSpecifities[spRenameView] := 'ALTER VIEW %s RENAME TO %s';
      FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER';
      FSQLSpecifities[spLikeCompare] := '%s ILIKE %s';
      FSQLSpecifities[spAddColumn] := 'ADD %s';
      FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s';
      FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s';
      FSQLSpecifities[spForeignKeyEventAction] :=
        'RESTRICT,CASCADE,SET NULL,NO ACTION,SET DEFAULT';
      FSQLSpecifities[spSessionVariables] := 'SHOW ALL';
      FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables];
      FSQLSpecifities[spISSchemaCol] := '%s_schema';
      FSQLSpecifities[spUSEQuery] := 'SET search_path TO %s';
      FSQLSpecifities[spKillQuery] := 'SELECT pg_cancel_backend(%d)';
      FSQLSpecifities[spKillProcess] := 'SELECT pg_cancel_backend(%d)';
      FSQLSpecifities[spFuncLength] := 'LENGTH';
      FSQLSpecifities[spFuncCeil] := 'CEIL';
      FSQLSpecifities[spFuncLeft] := 'SUBSTRING(%s, 1, %d)';
      FSQLSpecifities[spFuncNow] := 'NOW()';
      FSQLSpecifities[spFuncLastAutoIncNumber] := 'LASTVAL()';
      FSQLSpecifities[spLockedTables] := '';
      FSQLSpecifities[spDisableForeignKeyChecks] := '';
      FSQLSpecifities[spEnableForeignKeyChecks] := '';
    end;
    ngSQLite: begin
      FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s';
      FSQLSpecifities[spEmptyTable] := 'DELETE FROM ';
      FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s';
      FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable];
      FSQLSpecifities[spCurrentUserHost] := ''; // unsupported
      FSQLSpecifities[spLikeCompare] := '%s LIKE %s';
      FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s';
      FSQLSpecifities[spChangeColumn] := ''; // SQLite only supports renaming
      FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s';
      FSQLSpecifities[spSessionVariables] := 'SELECT null, null';
      // Todo: combine "PRAGMA pragma_list" + "PRAGMA a; PRAGMY b; ..."?
      FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES';
      FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA';
      FSQLSpecifities[spUSEQuery] := '';
      FSQLSpecifities[spKillQuery] := 'KILL %d';
      FSQLSpecifities[spKillProcess] := 'KILL %d';
      FSQLSpecifities[spFuncLength] := 'LENGTH';
      FSQLSpecifities[spFuncCeil] := 'CEIL';
      FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)';
      FSQLSpecifities[spFuncNow] := 'DATETIME()';
      FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
      FSQLSpecifities[spLockedTables] := '';
      FSQLSpecifities[spDisableForeignKeyChecks] := '';
      FSQLSpecifities[spEnableForeignKeyChecks] := '';
    end;
    ngInterbase: begin
      FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s';
      FSQLSpecifities[spEmptyTable] := 'TRUNCATE ';
      FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s';
      FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable];
      if Self.Parameters.LibraryOrProvider = 'IB' then
        FSQLSpecifities[spCurrentUserHost] := 'select user from rdb$database'
      else
        FSQLSpecifities[spCurrentUserHost] :=
          'select current_user || ''@'' || mon$attachments.mon$remote_host from mon$attachments where mon$attachments.mon$attachment_id = current_connection';
      FSQLSpecifities[spLikeCompare] := '%s LIKE %s';
      FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s';
      FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s';
      FSQLSpecifities[spRenameColumn] := '';
      FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES';
      FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES';
      FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA';
      FSQLSpecifities[spUSEQuery] := '';
      FSQLSpecifities[spKillQuery] := 'KILL %d';
      FSQLSpecifities[spKillProcess] := 'KILL %d';
      FSQLSpecifities[spFuncLength] := 'LENGTH';
      FSQLSpecifities[spFuncCeil] := 'CEIL';
      FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)';
      FSQLSpecifities[spFuncNow] := ' cast(''now'' as timestamp) from rdb$database';
      FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
      FSQLSpecifities[spLockedTables] := '';
      FSQLSpecifities[spDisableForeignKeyChecks] := '';
      FSQLSpecifities[spEnableForeignKeyChecks] := '';
    end;

  end;

end;

procedure TDBConnection.StartSSHTunnel(var FinalHost: string; var FinalPort: integer);
begin

end;

procedure TDBConnection.EndSSHTunnel;
begin

end;

procedure TDBConnection.DoAfterConnect;
begin

end;

procedure TDBConnection.DetectUSEQuery(SQL: string);
begin

end;

procedure TDBConnection.SetDatabase(Value: string);
begin

end;

function TDBConnection.GetCharacterSet: string;
begin

end;

procedure TDBConnection.SetCharacterSet(CharsetName: string);
begin

end;

function TDBConnection.GetAllDatabases: TStringList;
begin

end;

procedure TDBConnection.ApplyIgnoreDatabasePattern(Dbs: TStringList);
begin

end;

function TDBConnection.GetTableEngines: TStringList;
begin

end;

function TDBConnection.GetCollationTable: TDBQuery;
begin

end;

function TDBConnection.GetCollationList: TStringList;
begin

end;

function TDBConnection.GetCharsetTable: TDBQuery;
begin

end;

function TDBConnection.GetCharsetList: TStringList;
begin

end;

function TDBConnection.GetConnectionUptime: integer;
begin

end;

function TDBConnection.GetServerUptime: integer;
begin

end;

function TDBConnection.GetServerNow: TDateTime;
begin

end;

function TDBConnection.GetCurrentUserHostCombination: string;
begin

end;

function TDBConnection.GetAllUserHostCombinations: TStringList;
begin

end;

function TDBConnection.DecodeAPIString(a: ansistring): string;
begin

end;

procedure TDBConnection.ClearCache(IncludeDBObjects: boolean);
begin

end;

procedure TDBConnection.SetLockedByThread(Value: TThread);
begin

end;

procedure TDBConnection.KeepAliveTimerEvent(Sender: TObject);
begin

end;

procedure TDBConnection.Drop(Obj: TDBObject);
begin

end;

procedure TDBConnection.PrefetchResults(SQL: string);
begin

end;

procedure TDBConnection.FreeResults(Results: TDBQuery);
begin

end;

function TDBConnection.IsTextDefault(Value: string; Tp: TDBDatatype): boolean;
begin

end;

constructor TDBConnection.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TDBConnection.Destroy;
begin
  inherited Destroy;
end;

{**
   Executes a query
}
procedure TDBConnection.Query(SQL: string; DoStoreResult: boolean = False;
  LogCategory: TDBLogCategory = lcSQL);
begin
  if (FLockedByThread <> nil) and (FLockedByThread.ThreadID <> GetCurrentThreadID) then
  begin
    Log(lcDebug, _('Waiting for running query to finish ...'));
    try
      FLockedByThread.WaitFor;
    except
      on E: EThread do ;
    end;
  end;
  Ping(True);
  Log(LogCategory, SQL);
  FLastQuerySQL := SQL;
  FRowsFound := 0;
  FRowsAffected := 0;
  FWarningCount := 0;
end;


procedure TDBConnection.Log(Category: TDBLogCategory; Msg: string);
begin

end;

function TDBConnection.EscapeString(Text: string; ProcessJokerChars: boolean;
  DoQuote: boolean): string;
begin

end;

function TDBConnection.EscapeString(Text: string; Datatype: TDBDatatype): string;
begin

end;

function TDBConnection.QuoteIdent(Identifier: string; AlwaysQuote: boolean;
  Glue: char): string;
begin

end;

function TDBConnection.DeQuoteIdent(Identifier: string; Glue: char): string;
begin

end;

function TDBConnection.CleanIdent(Identifier: string): string;
begin

end;

function TDBConnection.QuotedDbAndTableName(DB, Obj: string): string;
begin

end;

function TDBConnection.FindObject(DB, Obj: string): TDBObject;
begin

end;

function TDBConnection.escChars(const Text: string;
  EscChar, Char1, Char2, Char3, Char4: char): string;
begin

end;

function TDBConnection.UnescapeString(Text: string): string;
begin

end;

function TDBConnection.ExtractLiteral(var SQL: string; Prefix: string): string;
begin

end;

function TDBConnection.GetResults(SQL: string): TDBQuery;
var
  Query: TDBQuery;
begin
  Result := nil;

  // Look up query result in cache
  if Assigned(FPrefetchResults) then
  begin
    for Query in FPrefetchResults do
    begin
      if Query.SQL = SQL then
      begin
        Result := Query;
        //Log(lcDebug, 'Using cached result for query: '+StrEllipsis(SQL, 100));
        Break;
      end;
    end;
  end;

  // Fire query
  if Result = nil then
  begin
    Result := Parameters.CreateQuery(Self);
    Result.SQL := SQL;
    try
      Result.Execute;
    except
      FreeAndNil(Result);
      raise;
    end;
  end;
end;

function TDBConnection.GetCol(SQL: string; Column: integer): TStringList;
var
  Results: TDBQuery;
begin
  Results := GetResults(SQL);
  Result := TStringList.Create;
  if Results.RecordCount > 0 then
    while not Results.EOF do
    begin
      Result.Add(Results.Col(Column));
      Results.Next;
    end;
  FreeResults(Results);
end;

{**
  Get single cell value via SQL query, identified by column number
}
function TDBConnection.GetVar(SQL: string; Column: integer = 0): string;
var
  Results: TDBQuery;
begin
  Results := GetResults(SQL);
  if Results.RecordCount > 0 then
    Result := Results.Col(Column)
  else
    Result := '';
  FreeResults(Results);
end;


{**
  Get single cell value via SQL query, identified by column name
}
function TDBConnection.GetVar(SQL: string; Column: string): string;
var
  Results: TDBQuery;
begin
  Results := GetResults(SQL);
  if Results.RecordCount > 0 then
    Result := Results.Col(Column)
  else
    Result := '';
  FreeResults(Results);
end;

function TDBConnection.RefreshAllDatabases: TStringList;
begin

end;

function TDBConnection.GetDBObjects(db: string; Refresh: boolean;
  OnlyNodeType: TListNodeType): TDBObjectList;
begin

end;

function TDBConnection.DbObjectsCached(db: string): boolean;
begin

end;

function TDBConnection.ParseDateTime(Str: string): TDateTime;
begin

end;

function TDBConnection.GetKeyColumns(Columns: TTableColumnList;
  Keys: TTableKeyList): TStringList;
begin

end;

function TDBConnection.ConnectionInfo: TStringList;
begin

end;

function TDBConnection.GetLastResults: TDBQueryList;
var
  r: TDBQuery;
  i: integer;
begin
  Result := TDBQueryList.Create(False);
  for i := 0 to ResultCount - 1 do
  begin
    r := Parameters.CreateQuery(Self);
    r.SQL := FLastQuerySQL;
    r.Execute(False, i);
    Result.Add(r);
  end;
end;

function TDBConnection.GetCreateCode(Obj: TDBObject): string;
begin

end;

procedure TDBConnection.PrefetchCreateCode(Objects: TDBObjectList);
begin

end;

function TDBConnection.GetSessionVariables(Refresh: boolean): TDBQuery;
begin

end;

function TDBConnection.GetSessionVariable(VarName: string; DefaultValue: string;
  Refresh: boolean): string;
begin

end;

function TDBConnection.MaxAllowedPacket: int64;
begin

end;

function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId): string;
begin

end;

function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId;
  const Args: array of const): string;
begin

end;

function TDBConnection.GetDateTimeValue(Input: string;
  Datatype: TDBDatatypeIndex): string;
begin

end;

procedure TDBConnection.ClearDbObjects(db: string);
begin

end;

procedure TDBConnection.ClearAllDbObjects;
begin

end;

procedure TDBConnection.ParseViewStructure(CreateCode: string;
  DBObj: TDBObject; var Algorithm, Definer, SQLSecurity, CheckOption,
  SelectCode: string);
begin

end;

procedure TDBConnection.ParseRoutineStructure(Obj: TDBObject;
  Parameters: TRoutineParamList);
begin

end;

procedure TDBConnection.PurgePrefetchResults;
begin

end;

function TDBConnection.GetDatatypeByName(var DataType: string;
  DeleteFromSource: boolean; Identifier: string): TDBDatatype;
begin

end;

function TDBConnection.GetDatatypeByNativeType(NativeType: integer;
  Identifier: string): TDBDatatype;
begin

end;

function TDBConnection.ApplyLimitClause(QueryType, QueryBody: string;
  Limit, Offset: int64): string;
begin

end;

function TDBConnection.LikeClauseTail: string;
begin

end;

function TDBConnection.ServerVersionStr: string;
begin

end;

function TDBConnection.ServerVersionInt: integer;
begin

end;

function TDBConnection.NdbClusterVersionInt: integer;
begin

end;

function TDBConnection.ResultCount: integer;
begin

end;

function TDBConnection.GetLockedTableCount(db: string): integer;
begin

end;

function TDBConnection.IdentifierEquals(Ident1, Ident2: string): boolean;
begin

end;

function TDBConnection.GetTableColumns(Table: TDBObject): TTableColumnList;
begin

end;

function TDBConnection.GetTableKeys(Table: TDBObject): TTableKeyList;
begin

end;

function TDBConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList;
begin

end;

function TDBConnection.GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList;
begin

end;

function TDBConnection.IsNumeric(Text: string): boolean;
begin

end;

function TDBConnection.IsHex(Text: string): boolean;
begin

end;

{ TGridValue }

destructor TGridValue.Destroy;
begin
  inherited Destroy;
end;

{ TSQLFunctionList }

constructor TSQLFunctionList.Create(AOwner: TDBConnection;
  SQLFunctionsFileOrder: string);
begin

end;

{ TMySQLConnection }

procedure TMySQLConnection.SetActive(Value: boolean);
begin

end;

procedure TMySQLConnection.DoBeforeConnect;
begin
  inherited DoBeforeConnect;
end;

procedure TMySQLConnection.DoAfterConnect;
begin
  inherited DoAfterConnect;
end;


function TMySQLConnection.GetCharacterSet: string;
begin
  Result := inherited GetCharacterSet;
end;

procedure TMySQLConnection.SetCharacterSet(CharsetName: string);
begin
  inherited SetCharacterSet(CharsetName);
end;

function TMySQLConnection.GetLastErrorCode: cardinal;
begin

end;

function TMySQLConnection.GetLastErrorMsg: string;
begin

end;

function TMySQLConnection.GetAllDatabases: TStringList;
begin
  Result := inherited GetAllDatabases;
end;

function TMySQLConnection.GetTableEngines: TStringList;
begin
  Result := inherited GetTableEngines;
end;

function TMySQLConnection.GetCollationTable: TDBQuery;
begin
  Result := inherited GetCollationTable;
end;

function TMySQLConnection.GetCharsetTable: TDBQuery;
begin
  Result := inherited GetCharsetTable;
end;

function TMySQLConnection.GetCreateViewCode(Database, Name: string): string;
begin

end;

function TMySQLConnection.GetRowCount(Obj: TDBObject; ForceExact: boolean): int64;
begin

end;

procedure TMySQLConnection.FetchDbObjects(db: string; var Cache: TDBObjectList);
begin

end;

procedure TMySQLConnection.SetLockedByThread(Value: TThread);
begin
  inherited SetLockedByThread(Value);
end;

constructor TMySQLConnection.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TMySQLConnection.Destroy;
begin
  inherited Destroy;
end;

procedure TMySQLConnection.Query(SQL: string; DoStoreResult: boolean;
  LogCategory: TDBLogCategory);
begin
  inherited Query(SQL, DoStoreResult, LogCategory);
end;

function TMySQLConnection.Ping(Reconnect: boolean): boolean;
begin

end;

function TMySQLConnection.ConnectionInfo: TStringList;
begin
  Result := inherited ConnectionInfo;
end;

function TMySQLConnection.GetCreateCode(Obj: TDBObject): string;
begin
  Result := inherited GetCreateCode(Obj);
end;

function TMySQLConnection.MaxAllowedPacket: int64;
begin
  Result := inherited MaxAllowedPacket;
end;

function TMySQLConnection.GetTableColumns(Table: TDBObject): TTableColumnList;
begin
  Result := inherited GetTableColumns(Table);
end;

function TMySQLConnection.GetTableKeys(Table: TDBObject): TTableKeyList;
begin
  Result := inherited GetTableKeys(Table);
end;

{ TAdoDBConnection }

procedure TAdoDBConnection.SetActive(Value: boolean);
var
  Error, NetLib, DataSource, QuotedPassword, ServerVersion, ErrorHint: string;
  FinalHost: string;
  rx: TRegExpr;
  FinalPort, i: integer;
  IsOldProvider: boolean;
  ret: TResultInfo;
begin
  if Value and (FHandle = nil) then
  begin
    DoBeforeConnect;

    // Get handle
    FHandle := qiuLib.qiusql_init(nil);

    qiuLib.GetSqlDbConn(self.Parameters.Id, FHandle);
    //FQiusqlID := ret.strid;

    //ret.strid;

    //  DoBeforeConnect;
    //  FinalHost := Parameters.Hostname;
    //  FinalPort := Parameters.Port;
    //  StartSSHTunnel(FinalHost, FinalPort);

    //  try
    //    // Creating the ADO object throws exceptions if MDAC is missing, especially on Wine
    //    FAdoHandle := TAdoConnection.Create(Owner);
    //  except
    //    on E: Exception do
    //      raise EDbError.Create(E.Message + CRLF + CRLF +
    //        _('On Wine, you can try to install MDAC:') + CRLF +
    //        '> wget http://winetricks.org/winetricks' + CRLF +
    //        '> chmod +x winetricks' + CRLF + '> sh winetricks mdac28' + CRLF +
    //        '> sh winetricks native_mdac');
    //  end;

    //  IsOldProvider := Parameters.LibraryOrProvider = 'SQLOLEDB';
    //  if IsOldProvider then
    //  begin
    //    MessageDialog(
    //      f_('Security issue: Using %s %s with insecure %s.',
    //      [Parameters.LibraryOrProvider, 'ADO provider', 'TLS 1.0']) +
    //      f_('You should install %s from %s', ['Microsoft OLE DB Driver',
    //      'https://www.microsoft.com/en-us/download/confirmation.aspx?id=56730']),
    //      mtWarning, [mbOK]);
    //  end;

    //  NetLib := '';
    //  case Parameters.NetType of
    //    ntMSSQL_NamedPipe: NetLib := 'DBNMPNTW';
    //    ntMSSQL_TCPIP: NetLib := 'DBMSSOCN';
    //    ntMSSQL_SPX: NetLib := 'DBMSSPXN';
    //    ntMSSQL_VINES: NetLib := 'DBMSVINN';
    //    ntMSSQL_RPC: NetLib := 'DBMSRPCN';
    //  end;

    //  DataSource := FinalHost;
    //  if (Parameters.NetType = ntMSSQL_TCPIP) and (FinalPort <> 0) then
    //    DataSource := DataSource + ',' + IntToStr(FinalPort);

    //  // Quote password, just in case there is a semicolon or a double quote in it.
    //  // See http://forums.asp.net/t/1957484.aspx?Passwords+ending+with+semi+colon+as+the+terminal+element+in+connection+strings+
    //  if Pos('"', Parameters.Password) > 0 then
    //    QuotedPassword := '''' + Parameters.Password + ''''
    //  else
    //    QuotedPassword := '"' + Parameters.Password + '"';

    //  FAdoHandle.ConnectionString :=
    //    'Provider=' + Parameters.LibraryOrProvider + ';' + 'Password=' + QuotedPassword + ';' +
    //    'Persist Security Info=True;' + 'User ID=' + Parameters.Username + ';' +
    //    'Network Library=' + NetLib + ';' + 'Data Source=' + DataSource + ';' +
    //    'Application Name=' + AppName + ';';
    //  if Parameters.LibraryOrProvider = 'MSOLEDBSQL' then
    //  begin
    //    // Issue #423: MSOLEDBSQL compatibility with new column types
    //    // See https://docs.microsoft.com/en-us/sql/connect/oledb/applications/using-ado-with-oledb-driver-for-sql-server?view=sql-server-2017
    //    // Do not use with old driver, see https://www.heidisql.com/forum.php?t=35208
    //    FAdoHandle.ConnectionString :=
    //      FAdoHandle.ConnectionString + 'DataTypeCompatibility=80;';
    //  end;

    //  // Pass Database setting to connection string. Required on MS Azure?
    //  if (not Parameters.AllDatabasesStr.IsEmpty) and
    //    (Pos(';', Parameters.AllDatabasesStr) = 0) then
    //    FAdoHandle.ConnectionString :=
    //      FAdoHandle.ConnectionString + 'Database=' + Parameters.AllDatabasesStr + ';';

    //  if Parameters.WindowsAuth then
    //  begin
    //    if IsOldProvider then
    //      FAdoHandle.ConnectionString :=
    //        FAdoHandle.ConnectionString + 'Integrated Security=SSPI;'
    //    else
    //      FAdoHandle.ConnectionString :=
    //        FAdoHandle.ConnectionString + 'Trusted_Connection=yes;';
    //  end;

    //  try
    //    FAdoHandle.Connected := True;
    //    FConnectionStarted := GetTickCount div 1000;
    //    FActive := True;
    //    // No need to set a charset for MS SQL
    //    // CharacterSet := 'utf8';
    //    // CurCharset := CharacterSet;
    //    // Log(lcDebug, 'Characterset: '+CurCharset);
    //    FAdoHandle.CommandTimeout := Parameters.QueryTimeout;
    try
      // Gracefully accept failure on MS Azure (SQL Server 11), which does not have a sysprocesses table
      FServerUptime := StrToIntDef(
        GetVar('SELECT DATEDIFF(SECOND, ' + QuoteIdent('login_time') +
        ', CURRENT_TIMESTAMP) FROM ' + QuoteIdent('master') +
        '.' + QuoteIdent('dbo') + '.' + QuoteIdent('sysprocesses') +
        ' WHERE ' + QuoteIdent('spid') + '=1'), -1);
    except
      FServerUptime := -1;
    end;
    FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow));
    // Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86)
    // Apr  2 2010 15:53:02
    // Copyright (c) Microsoft Corporation
    // Express Edition with Advanced Services on Windows NT 6.1 <X86> (Build 7600: )
    FServerVersionUntouched := Trim(GetVar('SELECT @@VERSION'));
    //    rx := TRegExpr.Create;
    //    rx.ModifierI := False;
    //    // Extract server OS
    //    rx.Expression := '\s+on\s+([^\r\n]+)';
    //    if rx.Exec(FServerVersionUntouched) then
    //      FServerOS := rx.Match[1];
    //    // Cut at first line break
    //    rx.Expression := '^([^\r\n]+)';
    //    if rx.Exec(FServerVersionUntouched) then
    //      FServerVersionUntouched := rx.Match[1];
    //    try
    //      // Try to get more exact server version to avoid displaying "20.14" in some cases
    //      ServerVersion := GetVar('SELECT SERVERPROPERTY(' + EscapeString(
    //        'ProductVersion') + ')');
    //      if ExecRegExpr('(\d+)\.(\d+)\.(\d+)\.(\d+)', ServerVersion) then
    //        FServerVersionUntouched :=
    //          Copy(FServerVersionUntouched, 1, Pos(' - ', FServerVersionUntouched) + 2) + ServerVersion;
    //    except
    //      // Above query only works on SQL Server 2008 and newer
    //      // Keep value from SELECT @@VERSION on older servers
    //    end;
    //    rx.Free;
    //    // See http://www.heidisql.com/forum.php?t=19779
    //    Query('SET TEXTSIZE 2147483647');
    //    FRealHostname := Parameters.Hostname;

    //    // Show up dynamic connection properties, probably useful for debugging
    //    for i := 0 to FAdoHandle.Properties.Count - 1 do
    //      Log(lcDebug, f_('OLE DB property "%s": %s',
    //        [FAdoHandle.Properties[i].Name, string(FAdoHandle.Properties[i].Value)]));

    //    // Triggers OnDatabaseChange event for <no db>
    //    Database := '';
    //    DoAfterConnect;

    //    // Reopen closed datasets after reconnecting
    //    // ... does not work for some reason. Still getting "not allowed on a closed object" errors in grid.
    //    //for i:=0 to FAdoHandle.DataSetCount-1 do
    //    //  FAdoHandle.DataSets[i].Open;

    //  except
    //    on E: Exception do
    //    begin
    //      FLastError := E.Message;
    //      Error := LastErrorMsg;
    //      Log(lcError, Error);
    //      FConnectionStarted := 0;
    //      if (FParameters.DefaultLibrary <> '') and
    //        (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then
    //      begin
    //        ErrorHint :=
    //          f_('You could try the default library %s in your session settings. (Current: %s)',
    //          [FParameters.DefaultLibrary, FParameters.LibraryOrProvider]);
    //      end
    //      else
    //      begin
    //        ErrorHint := '';
    //      end;
    //      raise EDbError.Create(Error, LastErrorCode, ErrorHint);
    //    end;
    //  end;
  end
  else
  begin
    //FAdoHandle.Connected := False;
    FActive := False;
    ClearCache(False);
    FConnectionStarted := 0;
    EndSSHTunnel;
    Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)]));
  end;
end;

procedure TAdoDBConnection.DoAfterConnect;
begin
  inherited DoAfterConnect;
end;


{**
  Return current thread id
  Supports 64bit process numbers on long running servers: https://dev.mysql.com/doc/refman/8.0/en/mysql-thread-id.html
  ... while ProxySQL does not support CONNECTION_ID()
}
function TMySQLConnection.GetThreadId: int64;
begin
  if FThreadId = 0 then
  begin
    Ping(False);
    if FActive then
    begin
      if Parameters.IsProxySQLAdmin then
        FThreadID := FLib.mysql_thread_id(FHandle)
      else
        FThreadID := StrToInt64Def(GetVar('SELECT CONNECTION_ID()'), 0);
    end;
  end;
  Result := FThreadID;
end;


function TAdoDBConnection.GetThreadId: int64;
begin
  if FThreadId = 0 then
  begin
    Ping(False);
    if FActive then
      FThreadID := StrToInt64Def(GetVar('SELECT @@SPID'), 0);
  end;
  Result := FThreadID;
end;


//function TPGConnection.GetThreadId: Int64;
//begin
//  if FThreadId = 0 then begin
//    Ping(False);
//    if FActive then
//      FThreadID := FLib.PQbackendPID(FHandle);
//  end;
//  Result := FThreadID;
//end;


function TSQLiteConnection.GetThreadId: int64;
begin
  if FThreadId = 0 then
  begin
    Ping(False);
    if FActive then;
    // We return the application process id, as there is no connection pid in SQLite
    //FThreadID := GetCurrentProcessId;
  end;
  Result := FThreadID;
end;


//function TInterbaseConnection.GetThreadId: Int64;
//begin
//  // Todo
//  Result := 0;
//end;

function TAdoDBConnection.GetLastErrorCode: cardinal;
begin

end;

function TAdoDBConnection.GetLastErrorMsg: string;
begin

end;

function TAdoDBConnection.GetAllDatabases: TStringList;
begin
  Result := inherited GetAllDatabases;
end;

function TAdoDBConnection.GetCollationTable: TDBQuery;
begin
  Result := inherited GetCollationTable;
end;

function TAdoDBConnection.GetCharsetTable: TDBQuery;
begin
  Result := inherited GetCharsetTable;
end;

function TAdoDBConnection.GetRowCount(Obj: TDBObject; ForceExact: boolean): int64;
begin

end;

procedure TAdoDBConnection.FetchDbObjects(db: string; var Cache: TDBObjectList);
begin

end;

constructor TAdoDBConnection.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TAdoDBConnection.Destroy;
begin
  inherited Destroy;
end;

procedure TAdoDBConnection.Query(SQL: string; DoStoreResult: boolean;
  LogCategory: TDBLogCategory);
var
  QueryStatus: integer;
  NativeSQL: ansistring;
  TimerStart: cardinal;
  QueryResult: PQIUSQL_RES;
  rowsID: PUint64;
begin
  inherited;

  if IsUnicode then
    NativeSQL := UTF8Encode(SQL)
  else
    NativeSQL := ansistring(SQL);
  TimerStart := GetTickCount64;
  SetLength(FLastRawResults, 0);
  FStatementNum := 1;
  QueryStatus := qiulib.qiusql_real_query(FHandle, pansichar(NativeSQL));//, rowsID);
  //QueryStatus := FLib.mysql_real_query(FHandle, pansichar(NativeSQL), Length(NativeSQL));
  FLastQueryDuration := GetTickCount64 - TimerStart;
  FLastQueryNetworkDuration := 0;
  if QueryStatus <> 0 then
  begin
    // Most errors will show up here, some others slightly later, after mysql_store_result()
    Log(lcError, GetLastErrorMsg);
    raise EDbError.Create(GetLastErrorMsg, GetLastErrorCode);
  end
  else
  begin
    // We must call mysql_store_result() + mysql_free_result() to unblock the connection
    // See: http://dev.mysql.com/doc/refman/5.0/en/mysql-store-result.html
    //FWarningCount := FLib.mysql_warning_count(FHandle); //SHOW WARNINGS – 显示最后一个执行语句所产生的警告信息
    TimerStart := GetTickCount64;
    //QueryResult := FLib.mysql_store_result(FHandle);

    QueryResult := qiulib.qiusql_store_result(FHandle);   //rowsID^
    FLastQueryNetworkDuration := GetTickCount64 - TimerStart;

    if (QueryResult = nil) then  //and (FLib.mysql_affected_rows(FHandle) = -1) then
    begin
      // Indicates a late error, e.g. triggered by mysql_store_result(), after selecting a stored
      // function with invalid SQL body. Also SHOW TABLE STATUS on older servers.
      // See http://dev.mysql.com/doc/refman/5.0/en/mysql-affected-rows.html
      //   "An integer greater than zero indicates the number of rows affected or
      //   retrieved. Zero indicates that no records were updated for an UPDATE statement, no rows
      //   matched the WHERE clause in the query or that no query has yet been executed. -1
      //   indicates that the query returned an error or that, for a SELECT query,
      //   mysql_affected_rows() was called prior to calling mysql_store_result()."
      Log(lcError, GetLastErrorMsg);
      raise EDbError.Create(GetLastErrorMsg);
    end;

    if QueryResult = nil then
      DetectUSEQuery(SQL);

    while QueryStatus = 0 do
    begin
      if QueryResult <> nil then
      begin
        // Statement returned a result set
        Inc(FRowsFound, QiuLib.qiusql_num_rows(QueryResult));   //Inc(FRowsFound, FLib.mysql_num_rows(QueryResult));
        if DoStoreResult then
        begin
          SetLength(FLastRawResults, Length(FLastRawResults) + 1);
          FLastRawResults[Length(FLastRawResults) - 1] := QueryResult;
        end
        else
        begin
          qiulib.qiusql_free_result(QueryResult);  //FLib.mysql_free_result(QueryResult);
        end;
      end
      else
      begin
        // No result, but probably affected rows
        Inc(FRowsAffected, qiuLib.qiusql_affected_rows(FHandle));                      //Inc(FRowsAffected, FLib.mysql_affected_rows(FHandle));
      end;
      // more results? -1 = no, >0 = error, 0 = yes (keep looping)
      Inc(FStatementNum);
      TimerStart := GetTickCount64;
      QueryStatus := qiuLib.qiusql_next_result(FHandle);                  //QueryStatus := FLib.mysql_next_result(FHandle);
      Inc(FLastQueryDuration, GetTickCount64 - TimerStart);
      if QueryStatus = 0 then
        QueryResult := qiulib.qiusql_store_result(FHandle)
      else if QueryStatus > 1 then     //else if QueryStatus > 0 then
      begin
        // MySQL stops executing a multi-query when an error occurs. So do we here by raising an exception.
        SetLength(FLastRawResults, 0);
        Log(lcError, GetLastErrorMsg);
        raise EDbError.Create(GetLastErrorMsg);
      end;
    end;

  end;
end;

function TAdoDBConnection.Ping(Reconnect: boolean): boolean;
begin

end;

function TAdoDBConnection.ConnectionInfo: TStringList;
begin
  Result := inherited ConnectionInfo;
end;

function TAdoDBConnection.GetLastResults: TDBQueryList;
begin
  Result := inherited GetLastResults;
end;

function TAdoDBConnection.GetTableColumns(Table: TDBObject): TTableColumnList;
begin
  Result := inherited GetTableColumns(Table);
end;

function TAdoDBConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList;
begin
  Result := inherited GetTableForeignKeys(Table);
end;

{ TSQLiteConnection }

procedure TSQLiteConnection.SetActive(Value: boolean);
begin

end;

procedure TSQLiteConnection.DoBeforeConnect;
begin
  inherited DoBeforeConnect;
end;


function TSQLiteConnection.GetLastErrorCode: cardinal;
begin

end;

function TSQLiteConnection.GetLastErrorMsg: string;
begin

end;

function TSQLiteConnection.GetAllDatabases: TStringList;
begin
  Result := inherited GetAllDatabases;
end;

function TSQLiteConnection.GetCollationList: TStringList;
begin
  Result := inherited GetCollationList;
end;

function TSQLiteConnection.GetCharsetTable: TDBQuery;
begin
  Result := inherited GetCharsetTable;
end;

procedure TSQLiteConnection.FetchDbObjects(db: string; var Cache: TDBObjectList);
begin

end;

constructor TSQLiteConnection.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TSQLiteConnection.Destroy;
begin
  inherited Destroy;
end;

procedure TSQLiteConnection.Query(SQL: string; DoStoreResult: boolean;
  LogCategory: TDBLogCategory);
begin
  inherited Query(SQL, DoStoreResult, LogCategory);
end;

function TSQLiteConnection.Ping(Reconnect: boolean): boolean;
begin

end;

function TSQLiteConnection.GetCreateCode(Obj: TDBObject): string;
begin
  Result := inherited GetCreateCode(Obj);
end;

function TSQLiteConnection.GetRowCount(Obj: TDBObject; ForceExact: boolean): int64;
begin

end;

function TSQLiteConnection.GetTableColumns(Table: TDBObject): TTableColumnList;
begin
  Result := inherited GetTableColumns(Table);
end;

function TSQLiteConnection.GetTableKeys(Table: TDBObject): TTableKeyList;
begin
  Result := inherited GetTableKeys(Table);
end;

function TSQLiteConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList;
begin
  Result := inherited GetTableForeignKeys(Table);
end;

{ TDBQuery }

function TDBQuery.ColumnExists(Column: integer): boolean;
begin

end;

procedure TDBQuery.SetColumnOrgNames(Value: TStringList);
begin

end;

procedure TDBQuery.SetDBObject(Value: TDBObject);
begin

end;

procedure TDBQuery.CreateUpdateRow;
begin

end;

function TDBQuery.GetKeyColumns: TStringList;
begin

end;

function TDBQuery.GridQuery(QueryType, QueryBody: string): string;
begin

end;

constructor TDBQuery.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FConnection := AOwner as TDbConnection;
  FRecNo := -1;
  FRecordCount := 0;
  FColumnNames := TStringList.Create;
  FColumnNames.CaseSensitive := False;
  FColumnOrgNames := TStringList.Create;
  FColumnOrgNames.CaseSensitive := False;
  FStoreResult := True;
  FDBObject := nil;
  //FFormatSettings := TFormatSettings.Create('en-US');  //lazarus里面也是记录体 但是无create方法  工程里的FormatSettings这个全局的也有
end;

destructor TDBQuery.Destroy;
begin
  FreeAndNil(FColumnNames);
  FreeAndNil(FColumnOrgNames);
  FreeAndNil(FColumns);
  FreeAndNil(FKeys);
  FreeAndNil(FUpdateData);
  if FDBObject <> nil then
    FDBObject.Free;
  SetLength(FColumnFlags, 0);
  SetLength(FColumnLengths, 0);
  SetLength(FColumnTypes, 0);
  FSQL := '';
  FRecordCount := 0;
  inherited;
end;

procedure TDBQuery.First;
begin

end;

procedure TDBQuery.Next;
begin

end;

function TDBQuery.ColumnCount: integer;
begin

end;

function TDBQuery.GetColBinData(Column: integer; var baData: TBytes): boolean;
begin

end;

function TDBQuery.Col(ColumnName: string; IgnoreErrors: boolean): string;
begin

end;

function TDBQuery.ColumnLengths(Column: integer): int64;
begin

end;

function TDBQuery.HexValue(Column: integer; IgnoreErrors: boolean): string;
begin

end;

function TDBQuery.HexValue(BinValue: string): string;
begin

end;

function TDBQuery.HexValue(var ByteData: TBytes): string;
begin

end;

function TDBQuery.DataType(Column: integer): TDBDataType;
begin

end;

function TDBQuery.MaxLength(Column: integer): int64;
begin

end;

function TDBQuery.ValueList(Column: integer): TStringList;
begin

end;

function TDBQuery.ColExists(Column: string): boolean;
begin

end;

function TDBQuery.ColIsVirtual(Column: integer): boolean;
begin

end;

function TDBQuery.ColAttributes(Column: integer): TTableColumn;
begin

end;

function TDBQuery.IsNull(Column: string): boolean;
begin

end;

function TDBQuery.IsFunction(Column: integer): boolean;
begin

end;

function TDBQuery.GetWhereClause: string;
begin

end;

procedure TDBQuery.CheckEditable;
begin

end;

function TDBQuery.IsEditable: boolean;
begin

end;

procedure TDBQuery.DeleteRow;
begin

end;

function TDBQuery.InsertRow: int64;
begin

end;

procedure TDBQuery.SetCol(Column: integer; NewText: string; Null: boolean;
  IsFunction: boolean);
begin

end;

function TDBQuery.EnsureFullRow(Refresh: boolean): boolean;
begin

end;

function TDBQuery.HasFullData: boolean;
begin

end;

function TDBQuery.Modified(Column: integer): boolean;
begin

end;

function TDBQuery.Modified: boolean;
begin

end;

function TDBQuery.Inserted: boolean;
begin

end;

function TDBQuery.SaveModifications: boolean;
begin

end;

function TDBQuery.TableName: string;
begin

end;

function TDBQuery.QuotedDbAndTableName: string;
begin

end;

procedure TDBQuery.DiscardModifications;
begin

end;

procedure TDBQuery.PrepareColumnAttributes;
begin

end;

procedure TDBQuery.PrepareEditing;
begin

end;

{ TMySQLQuery }

procedure TMySQLQuery.SetRecNo(Value: int64);
begin

end;

constructor TMySQLQuery.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  // suspicous state here - what type has FConnection now?
  FConnection := AOwner as TMySQLConnection;
end;


destructor TMySQLQuery.Destroy;
var
  i: Integer;
begin
  if HasResult and (FConnection <> nil) and (FConnection.Active) then begin
    for i:=Low(FResultList) to High(FResultList) do
       FConnection.Lib.mysql_free_result(FResultList[i]);
  end;
  SetLength(FResultList, 0);
  inherited;
end;

procedure TMySQLQuery.Execute(AddResult: boolean; UseRawResult: integer);
begin

end;

function TMySQLQuery.GetColBinData(Column: integer; var baData: TBytes): boolean;
begin
  Result := inherited GetColBinData(Column, baData);
end;

function TMySQLQuery.Col(Column: integer; IgnoreErrors: boolean): string;
begin
  //Result:=inherited Col(Column, IgnoreErrors);
end;

function TMySQLQuery.ColIsPrimaryKeyPart(Column: integer): boolean;
begin

end;

function TMySQLQuery.ColIsUniqueKeyPart(Column: integer): boolean;
begin

end;

function TMySQLQuery.ColIsKeyPart(Column: integer): boolean;
begin

end;

function TMySQLQuery.IsNull(Column: integer): boolean;
begin
  //Result:=inherited IsNull(Column);
end;

function TMySQLQuery.HasResult: boolean;
begin

end;

function TMySQLQuery.DatabaseName: string;
begin

end;

function TMySQLQuery.TableName(Column: integer): string;
begin

end;

{ TAdoDBQuery }

procedure TAdoDBQuery.SetRecNo(Value: int64);
begin

end;

destructor TAdoDBQuery.Destroy;
begin
  inherited Destroy;
end;

procedure TAdoDBQuery.Execute(AddResult: boolean = False; UseRawResult: integer = -1);
var
  i, j, NumFields, NumResults: integer;
  Field: PQIUSQL_FIELD;
  IsBinary: boolean;
  LastResult: PQIUSQL_RES;
begin
  // Execute a query, or just take over one of the last result pointers
  //if UseRawResult = -1 then
  //begin
  //  Connection.Query(FSQL, FStoreResult);
  //  UseRawResult := 0;
  //end;
  //if Connection.ResultCount > UseRawResult then
  //begin
  //  LastResult := TMySQLConnection(Connection).LastRawResults[UseRawResult];
  //end
  //else
  //begin
  //  LastResult := nil;
  //end;
  //if AddResult and (Length(FResultList) = 0) then
  //  AddResult := False;
  //if AddResult then
  //  NumResults := Length(FResultList) + 1
  //else
  //begin
  //  for i := Low(FResultList) to High(FResultList) do
  //  begin
  //    FConnection.Lib.mysql_free_result(FResultList[i]);
  //  end;
  //  SetLength(FResultList, 0);
  //  NumResults := 1;
  //  FRecordCount := 0;
  //  FAutoIncrementColumn := -1;
  //  FEditingPrepared := False;
  //end;
  //if LastResult <> nil then
  //begin
  //  Connection.Log(lcDebug, 'Result #' + IntToStr(NumResults) + ' fetched.');
  //  SetLength(FResultList, NumResults);
  //  FResultList[NumResults - 1] := LastResult;
  //  FRecordCount := FRecordCount + LastResult.row_count;
  //end;
  //if not AddResult then
  //begin
  //  if HasResult then
  //  begin
  //    // FCurrentResults is normally done in SetRecNo, but never if result has no rows
  //    FCurrentResults := LastResult;
  //    NumFields := FConnection.Lib.mysql_num_fields(LastResult);
  //    SetLength(FColumnTypes, NumFields);
  //    SetLength(FColumnLengths, NumFields);
  //    SetLength(FColumnFlags, NumFields);
  //    FColumnNames.Clear;
  //    FColumnOrgNames.Clear;
  //    for i := 0 to NumFields - 1 do
  //    begin
  //      Field := FConnection.Lib.mysql_fetch_field_direct(LastResult, i);
  //      FColumnNames.Add(Connection.DecodeAPIString(Field.Name));
  //      if Connection.ServerVersionInt >= 40100 then
  //        FColumnOrgNames.Add(Connection.DecodeAPIString(Field.org_name))
  //      else
  //        FColumnOrgNames.Add(Connection.DecodeAPIString(Field.Name));
  //      FColumnFlags[i] := Field.flags;
  //      FColumnTypes[i] := FConnection.Datatypes[0];
  //      if (Field.flags and AUTO_INCREMENT_FLAG) = AUTO_INCREMENT_FLAG then
  //        FAutoIncrementColumn := i;
  //      for j := 0 to High(FConnection.Datatypes) do
  //      begin
  //        if (Field.flags and ENUM_FLAG) = ENUM_FLAG then
  //        begin
  //          if FConnection.Datatypes[j].Index = dbdtEnum then
  //            FColumnTypes[i] := FConnection.Datatypes[j];
  //        end
  //        else if (Field.flags and SET_FLAG) = SET_FLAG then
  //        begin
  //          if FConnection.Datatypes[j].Index = dbdtSet then
  //            FColumnTypes[i] := FConnection.Datatypes[j];
  //        end
  //        else if Field._type = cardinal(FConnection.Datatypes[j].NativeType) then
  //        begin
  //          // Text and Blob types share the same constants (see FIELD_TYPEs)
  //          // See http://dev.mysql.com/doc/refman/5.7/en/c-api-data-structures.html
  //          if Connection.IsUnicode then
  //            IsBinary := Field.charsetnr = COLLATION_BINARY
  //          else
  //            IsBinary := (Field.flags and BINARY_FLAG) = BINARY_FLAG;
  //          if IsBinary and (FConnection.Datatypes[j].Category = dtcText) then
  //            continue;
  //          FColumnTypes[i] := FConnection.Datatypes[j];
  //          Break;
  //        end;
  //      end;
  //      FConnection.Log(lcDebug, 'Detected column type for ' +
  //        FColumnNames[i] + ' (' + IntToStr(Field._type) + '): ' + FColumnTypes[i].Name);
  //    end;
  //    FRecNo := -1;
  //    First;
  //  end
  //  else
  //  begin
  //    SetLength(FColumnTypes, 0);
  //    SetLength(FColumnLengths, 0);
  //    SetLength(FColumnFlags, 0);
  //  end;
  //end;
end;

function TAdoDBQuery.Col(Column: integer; IgnoreErrors: boolean): string;
begin
  //Result:=inherited Col(Column, IgnoreErrors);
end;

function TAdoDBQuery.ColIsPrimaryKeyPart(Column: integer): boolean;
begin

end;

function TAdoDBQuery.ColIsUniqueKeyPart(Column: integer): boolean;
begin

end;

function TAdoDBQuery.ColIsKeyPart(Column: integer): boolean;
begin

end;

function TAdoDBQuery.IsNull(Column: integer): boolean;
begin
  //Result:=inherited IsNull(Column);
end;

function TAdoDBQuery.HasResult: boolean;
begin

end;

function TAdoDBQuery.DatabaseName: string;
begin

end;

function TAdoDBQuery.TableName(Column: integer): string;
begin

end;

{ TSQLiteQuery }

procedure TSQLiteQuery.SetRecNo(Value: int64);
begin

end;

constructor TSQLiteQuery.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TSQLiteQuery.Destroy;
begin
  inherited Destroy;
end;

procedure TSQLiteQuery.Execute(AddResult: boolean; UseRawResult: integer);
begin

end;

function TSQLiteQuery.Col(Column: integer; IgnoreErrors: boolean): string;
begin
  //Result:=inherited Col(Column, IgnoreErrors);
end;

function TSQLiteQuery.ColIsPrimaryKeyPart(Column: integer): boolean;
begin

end;

function TSQLiteQuery.ColIsUniqueKeyPart(Column: integer): boolean;
begin

end;

function TSQLiteQuery.ColIsKeyPart(Column: integer): boolean;
begin

end;

function TSQLiteQuery.IsNull(Column: integer): boolean;
begin
  //Result:=inherited IsNull(Column);
end;

function TSQLiteQuery.HasResult: boolean;
begin

end;

function TSQLiteQuery.DatabaseName: string;
begin

end;

function TSQLiteQuery.TableName(Column: integer): string;
begin

end;

{ TDBObject }

function TDBObject.GetObjType: string;
begin

end;

function TDBObject.GetImageIndex: integer;
begin

end;

function TDBObject.GetOverlayImageIndex: integer;
begin

end;

function TDBObject.GetPath: string;
begin

end;

function TDBObject.GetTableColumns: TTableColumnList;
begin

end;

function TDBObject.GetTableKeys: TTableKeyList;
begin

end;

function TDBObject.GetTableForeignKeys: TForeignKeyList;
begin

end;

function TDBObject.GetTableCheckConstraints: TCheckConstraintList;
begin

end;

constructor TDBObject.Create(OwnerConnection: TDBConnection);
begin
  NodeType := lntNone;
  GroupType := lntNone;
  Name := '';
  Database := '';
  Schema := '';
  Rows := -1;
  Size := -1;
  Created := 0;
  Updated := 0;
  Engine := '';
  Comment := '';
  Version := -1;
  AutoInc := -1;
  RowFormat := '';
  AvgRowLen := -1;
  MaxDataLen := -1;
  IndexLen := -1;
  DataLen := -1;
  DataFree := -1;
  LastChecked := 0;
  Collation := '';
  CheckSum := -1;
  CreateOptions := '';
  FCreateCode := '';
  FCreateCodeLoaded := False;
  RowsAreExact := False;
  FConnection := OwnerConnection;
end;

procedure TDBObject.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
end;

procedure TDBObject.UnloadDetails;
begin

end;

procedure TDBObject.Drop;
begin

end;

function TDBObject.IsSameAs(CompareTo: TDBObject): boolean;
begin

end;

function TDBObject.QuotedDatabase(AlwaysQuote: boolean): string;
begin

end;

function TDBObject.QuotedName(AlwaysQuote: boolean; SeparateSegments: boolean): string;
begin

end;

function TDBObject.QuotedDbAndTableName(AlwaysQuote: boolean): string;
begin

end;

function TDBObject.QuotedColumn(AlwaysQuote: boolean): string;
begin

end;

function TDBObject.SchemaClauseIS(Prefix: string): string;
begin

end;

function TDBObject.RowCount(Reload: boolean; ForceExact: boolean): int64;
begin

end;

function TDBObject.GetCreateCode: string;
begin

end;

function TDBObject.GetCreateCode(RemoveAutoInc, RemoveDefiner: boolean): string;
begin

end;

{ TTableColumn }

procedure TTableColumn.SetStatus(Value: TEditingStatus);
begin

end;

constructor TTableColumn.Create(AOwner: TDBConnection; Serialized: string);
begin

end;

destructor TTableColumn.Destroy;
begin
  inherited Destroy;
end;

procedure TTableColumn.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
end;

function TTableColumn.Serialize: string;
begin

end;

function TTableColumn.SQLCode(OverrideCollation: string; Parts: TColumnParts): string;
begin

end;

function TTableColumn.ValueList: TStringList;
begin

end;

procedure TTableColumn.ParseDatatype(Source: string);
begin

end;

function TTableColumn.CastAsText: string;
begin

end;

function TTableColumn.AutoIncName: string;
begin

end;

{ TTableColumnList }

procedure TTableColumnList.Assign(Source: TTableColumnList);
begin

end;

{ TTableKey }

function TTableKey.GetImageIndex: integer;
begin

end;

constructor TTableKey.Create(AOwner: TDBConnection);
begin

end;

destructor TTableKey.Destroy;
begin
  inherited Destroy;
end;

procedure TTableKey.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
end;

procedure TTableKey.Modification(Sender: TObject);
begin

end;

function TTableKey.SQLCode: string;
begin

end;

{ TTableKeyList }

procedure TTableKeyList.Assign(Source: TTableKeyList);
begin

end;

{ TForeignKey }

constructor TForeignKey.Create(AOwner: TDBConnection);
begin

end;

destructor TForeignKey.Destroy;
begin
  inherited Destroy;
end;

procedure TForeignKey.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
end;

function TForeignKey.SQLCode(IncludeSymbolName: boolean): string;
begin

end;

function TForeignKey.ReferenceTableObj: TDBObject;
begin

end;

{ TForeignKeyList }

procedure TForeignKeyList.Assign(Source: TForeignKeyList);
begin

end;

{ TCheckConstraint }

constructor TCheckConstraint.Create(AOwner: TDBConnection);
begin

end;

procedure TCheckConstraint.Assign(Source: TPersistent);
begin
  inherited Assign(Source);
end;

function TCheckConstraint.SQLCode: string;
begin

end;

{ TCheckConstraintList }

procedure TCheckConstraintList.Assign(Source: TCheckConstraintList);
begin

end;

//function TConnectionParameters.GetExternalCliArguments(
//  Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String;
//begin

//end;

end.
